summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2023-11-14 10:12:10 +0100
committerThomas Haller <thaller@redhat.com>2023-11-16 13:07:53 +0100
commit901a1b096bf0617d1bcca5eed6b7ecc82e8eb583 (patch)
treefe7691f2fcad3f137f46659084fabf8f1e0924d0
parent83a1ce39b05a18227d8a1674bffba482c807ce45 (diff)
core: support "${NETWORK_SSID}" for connection.stable-id
For Wi-Fi profiles, this will encode the SSID in the stable-id. For other profiles, this encodes the connection UUID (but the SSID and the UUID will always result in distinct stable IDs). Also escape the SSID, so that the generated stable-id is always valid UTF-8.
-rw-r--r--NEWS2
-rw-r--r--src/core/devices/nm-device.c5
-rw-r--r--src/core/nm-core-utils.c25
-rw-r--r--src/core/nm-core-utils.h1
-rw-r--r--src/core/tests/test-core.c30
-rw-r--r--src/libnm-core-impl/nm-setting-connection.c16
-rw-r--r--src/libnmc-setting/settings-docs.h.in2
-rw-r--r--src/nmcli/gen-metadata-nm-settings-nmcli.xml.in2
8 files changed, 68 insertions, 15 deletions
diff --git a/NEWS b/NEWS
index cd46906b50..336e276168 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,8 @@ NetworkManager-1.46
Overview of changes since NetworkManager-1.44
=============================================
+* Support dynamic value "${NETWORK_SSID}" for connection.stable-id to generate
+ the stable ID based on the Wi-Fi's SSID.
* Change internal ABI of NMSetting types and NMSimpleConnection. The layout of
these structs was already hidden from public headers since 1.34 and this change
should not be noticeable.
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 7a2b9e1060..1edfaebf84 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -1033,12 +1033,14 @@ _prop_get_connection_stable_id(NMDevice *self,
gs_free char *generated = NULL;
NMUtilsStableType stable_type;
NMSettingConnection *s_con;
+ NMSettingWireless *s_wifi;
gboolean hwaddr_is_fake;
const char *hwaddr;
const char *stable_id;
const char *uuid;
- s_con = nm_connection_get_setting_connection(connection);
+ s_con = nm_connection_get_setting_connection(connection);
+ s_wifi = nm_connection_get_setting_wireless(connection);
stable_id = nm_setting_connection_get_stable_id(s_con);
@@ -1061,6 +1063,7 @@ _prop_get_connection_stable_id(NMDevice *self,
!hwaddr_is_fake ? hwaddr : NULL,
nm_utils_boot_id_str(),
uuid,
+ s_wifi ? nm_setting_wireless_get_ssid(s_wifi) : NULL,
&generated);
/* current_stable_id_type is a bitfield! */
diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c
index 9d3bb9582e..06b93f17ba 100644
--- a/src/core/nm-core-utils.c
+++ b/src/core/nm-core-utils.c
@@ -3397,6 +3397,7 @@ nm_utils_stable_id_parse(const char *stable_id,
const char *hwaddr,
const char *bootid,
const char *uuid,
+ GBytes *ssid,
char **out_generated)
{
nm_auto_str_buf NMStrBuf str = NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_232, FALSE);
@@ -3482,7 +3483,29 @@ nm_utils_stable_id_parse(const char *stable_id,
_stable_id_append(&str, deviceid);
else if (CHECK_PREFIX("${MAC}"))
_stable_id_append(&str, hwaddr);
- else if (g_str_has_prefix(&stable_id[i], "${RANDOM}")) {
+ else if (CHECK_PREFIX("${NETWORK_SSID}")) {
+ gs_free char *value_free = NULL;
+ gs_free char *s = NULL;
+ const char *value;
+ const char *type_id;
+
+ if (ssid) {
+ type_id = "s:";
+ value = nm_utils_buf_utf8safe_escape_bytes(ssid,
+ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL,
+ &value_free);
+ } else {
+ /* If we have no SSID, we fallback to the connection's UUID.
+ *
+ * Give a separate prefix (@type_id), so that an SSID and a UUID
+ * fallback never result in the same output. */
+ type_id = "c:";
+ value = uuid ?: "";
+ }
+
+ s = g_strjoin("", type_id, value, NULL);
+ _stable_id_append(&str, s);
+ } else if (g_str_has_prefix(&stable_id[i], "${RANDOM}")) {
/* RANDOM makes not so much sense for cloned-mac-address
* as the result is similar to specifying "cloned-mac-address=random".
* It makes however sense for RFC 7217 Stable Privacy IPv6 addresses
diff --git a/src/core/nm-core-utils.h b/src/core/nm-core-utils.h
index d73cfd6467..ec72690b07 100644
--- a/src/core/nm-core-utils.h
+++ b/src/core/nm-core-utils.h
@@ -313,6 +313,7 @@ NMUtilsStableType nm_utils_stable_id_parse(const char *stable_id,
const char *hwaddr,
const char *bootid,
const char *uuid,
+ GBytes *ssid,
char **out_generated);
char *nm_utils_stable_id_random(void);
diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c
index 8296d74579..01d2782012 100644
--- a/src/core/tests/test-core.c
+++ b/src/core/tests/test-core.c
@@ -2104,8 +2104,19 @@ do_test_stable_id_parse(const char *stable_id,
NMUtilsStableType expected_stable_type,
const char *expected_generated)
{
- gs_free char *generated = NULL;
- NMUtilsStableType stable_type;
+ gs_free char *generated = NULL;
+ NMUtilsStableType stable_type;
+ char ssid_bin[] = "SSID(\202)";
+ gs_unref_bytes GBytes *ssid = g_bytes_new_static(ssid_bin, sizeof(ssid_bin) - 1);
+
+ while (TRUE) {
+ if (NM_STR_HAS_PREFIX(stable_id, "NO_SSID:")) {
+ stable_id += NM_STRLEN("NO_SSID:");
+ nm_clear_pointer(&ssid, g_bytes_unref);
+ continue;
+ }
+ break;
+ }
if (expected_stable_type == NM_UTILS_STABLE_TYPE_GENERATED)
g_assert(expected_generated);
@@ -2117,8 +2128,13 @@ do_test_stable_id_parse(const char *stable_id,
else
g_assert(stable_id);
- stable_type =
- nm_utils_stable_id_parse(stable_id, "_DEVICE", "_MAC", "_BOOT", "_CONNECTION", &generated);
+ stable_type = nm_utils_stable_id_parse(stable_id,
+ "_DEVICE",
+ "_MAC",
+ "_BOOT",
+ "_CONNECTION",
+ ssid,
+ &generated);
g_assert_cmpint(expected_stable_type, ==, stable_type);
@@ -2160,6 +2176,12 @@ test_stable_id_parse(void)
_parse_generated("${${CONNECTION}", "${${CONNECTION}=11{_CONNECTION}");
_parse_generated("${CONNECTION}x", "${CONNECTION}=11{_CONNECTION}x");
_parse_generated("x${CONNECTION}", "x${CONNECTION}=11{_CONNECTION}");
+ _parse_generated("x${CONNECTION}${NETWORK_SSID}",
+ "x${CONNECTION}=11{_CONNECTION}${NETWORK_SSID}=12{s:SSID(\\202)}");
+ _parse_generated("NO_SSID:x${CONNECTION}${NETWORK_SSID}",
+ "x${CONNECTION}=11{_CONNECTION}${NETWORK_SSID}=13{c:_CONNECTION}");
+ _parse_generated("${NETWORK_SSID}", "${NETWORK_SSID}=12{s:SSID(\\202)}");
+ _parse_generated("NO_SSID:${NETWORK_SSID}", "${NETWORK_SSID}=13{c:_CONNECTION}");
_parse_generated("${BOOT}x", "${BOOT}=5{_BOOT}x");
_parse_generated("x${BOOT}", "x${BOOT}=5{_BOOT}");
_parse_generated("x${BOOT}${CONNECTION}", "x${BOOT}=5{_BOOT}${CONNECTION}=11{_CONNECTION}");
diff --git a/src/libnm-core-impl/nm-setting-connection.c b/src/libnm-core-impl/nm-setting-connection.c
index a228ecf0c5..28f3b24c69 100644
--- a/src/libnm-core-impl/nm-setting-connection.c
+++ b/src/libnm-core-impl/nm-setting-connection.c
@@ -1928,13 +1928,15 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
*
* The '$' character is treated special to perform dynamic substitutions at
* activation time. Currently, supported are "${CONNECTION}", "${DEVICE}",
- * "${MAC}", "${BOOT}", "${RANDOM}". These effectively create unique IDs
- * per-connection, per-device, per-boot, or every time. The "${CONNECTION}"
- * uses the profile's connection.uuid, the "${DEVICE}" uses the interface
- * name of the device and "${MAC}" the permanent MAC address 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
+ * "${MAC}", "${NETWORK_SSID}", "${BOOT}", "${RANDOM}". These effectively
+ * create unique IDs per-connection, per-device, per-SSID, per-boot, or
+ * every time. The "${CONNECTION}" uses the profile's connection.uuid, the
+ * "${DEVICE}" uses the interface name of the device and "${MAC}" the
+ * permanent MAC address of the device. "${NETWORK_SSID}" uses the SSID for
+ * Wi-Fi networks and falls back to "${CONNECTION}" on other networks. 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.
*
diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in
index beb2e56fcf..634bdf600e 100644
--- a/src/libnmc-setting/settings-docs.h.in
+++ b/src/libnmc-setting/settings-docs.h.in
@@ -21,7 +21,7 @@
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("This property is deprecated and has no meaning.")
#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 to derive the DHCP client identifier with ipv4.dhcp-client-id=stable, the DHCPv6 DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid] and the DHCP IAID with ipv4.iaid=stable and ipv6.iaid=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 per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The '$' character is treated special to perform dynamic substitutions at activation time. Currently, supported are \"${CONNECTION}\", \"${DEVICE}\", \"${MAC}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. The \"${CONNECTION}\" uses the profile's connection.uuid, the \"${DEVICE}\" uses the interface name of the device and \"${MAC}\" the permanent MAC address 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 \"default${CONNECTION}\" go generate an ID unique per connection profile.")
+#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 to derive the DHCP client identifier with ipv4.dhcp-client-id=stable, the DHCPv6 DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid] and the DHCP IAID with ipv4.iaid=stable and ipv6.iaid=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 per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The '$' character is treated special to perform dynamic substitutions at activation time. Currently, supported are \"${CONNECTION}\", \"${DEVICE}\", \"${MAC}\", \"${NETWORK_SSID}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-SSID, per-boot, or every time. The \"${CONNECTION}\" uses the profile's connection.uuid, the \"${DEVICE}\" uses the interface name of the device and \"${MAC}\" the permanent MAC address of the device. \"${NETWORK_SSID}\" uses the SSID for Wi-Fi networks and falls back to \"${CONNECTION}\" on other networks. 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 \"default${CONNECTION}\" go generate an ID unique per connection profile.")
#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_("The connection.uuid is the real identifier of a profile. It cannot change and it must be unique. It is therefore often best to refer to a profile by UUID, for example with `nmcli connection up uuid $UUID`. The UUID cannot be changed, except in offline mode. In that case, the special values \"new\", \"generate\" and \"\" are allowed to generate a new random UUID.")
diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
index ed06e92968..2b9bd14837 100644
--- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
+++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
@@ -610,7 +610,7 @@
nmcli-description="The connection.uuid is the real identifier of a profile. It cannot change and it must be unique. It is therefore often best to refer to a profile by UUID, for example with `nmcli connection up uuid $UUID`. The UUID cannot be changed, except in offline mode. In that case, the special values &quot;new&quot;, &quot;generate&quot; and &quot;&quot; are allowed to generate a new random UUID."
format="string" />
<property name="stable-id"
- nmcli-description="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 to derive the DHCP client identifier with ipv4.dhcp-client-id=stable, the DHCPv6 DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid] and the DHCP IAID with ipv4.iaid=stable and ipv6.iaid=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&apos;s name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The &apos;$&apos; character is treated special to perform dynamic substitutions at activation time. Currently, supported are &quot;${CONNECTION}&quot;, &quot;${DEVICE}&quot;, &quot;${MAC}&quot;, &quot;${BOOT}&quot;, &quot;${RANDOM}&quot;. These effectively create unique IDs per-connection, per-device, per-boot, or every time. The &quot;${CONNECTION}&quot; uses the profile&apos;s connection.uuid, the &quot;${DEVICE}&quot; uses the interface name of the device and &quot;${MAC}&quot; the permanent MAC address of the device. Any unrecognized patterns following &apos;$&apos; are treated verbatim, however are reserved for future use. You are thus advised to avoid &apos;$&apos; or escape it as &quot;$$&quot;. For example, set it to &quot;${CONNECTION}-${BOOT}-${DEVICE}&quot; 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 &quot;default${CONNECTION}&quot; go generate an ID unique per connection profile."
+ nmcli-description="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 to derive the DHCP client identifier with ipv4.dhcp-client-id=stable, the DHCPv6 DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid] and the DHCP IAID with ipv4.iaid=stable and ipv6.iaid=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&apos;s name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The &apos;$&apos; character is treated special to perform dynamic substitutions at activation time. Currently, supported are &quot;${CONNECTION}&quot;, &quot;${DEVICE}&quot;, &quot;${MAC}&quot;, &quot;${NETWORK_SSID}&quot;, &quot;${BOOT}&quot;, &quot;${RANDOM}&quot;. These effectively create unique IDs per-connection, per-device, per-SSID, per-boot, or every time. The &quot;${CONNECTION}&quot; uses the profile&apos;s connection.uuid, the &quot;${DEVICE}&quot; uses the interface name of the device and &quot;${MAC}&quot; the permanent MAC address of the device. &quot;${NETWORK_SSID}&quot; uses the SSID for Wi-Fi networks and falls back to &quot;${CONNECTION}&quot; on other networks. Any unrecognized patterns following &apos;$&apos; are treated verbatim, however are reserved for future use. You are thus advised to avoid &apos;$&apos; or escape it as &quot;$$&quot;. For example, set it to &quot;${CONNECTION}-${BOOT}-${DEVICE}&quot; 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 &quot;default${CONNECTION}&quot; go generate an ID unique per connection profile."
format="string" />
<property name="type"
alias="type"