summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-05-22 18:35:43 +0200
committerThomas Haller <thaller@redhat.com>2018-05-28 11:37:17 +0200
commitc4c591606b82144ec9b860212c12b6e9d98b9f70 (patch)
tree7e68deda0b6a3dc8d7d188678cce6825f82ce946
parent93cd5bd233d39b8fbce3efa6eaa168448cfa9609 (diff)
downloadNetworkManager-c4c591606b82144ec9b860212c12b6e9d98b9f70.tar.gz
all: add stable-id specifiers "${HOST}" and "${DEVICE}"
Add two new stable-id specifiers "${HOST}" and "${DEVICE}" to explicitly declare that the connection's identity differs per-host or per-device. Note that for settings like "ipv6.addr-gen-mode=stable" we already hash the host's secret-key and the interface's name. So, for addr-gen-mode, using these specifiers has no real use. But for example, we don't do that for "ipv4.dhcp-client-id=stable". Currently, "ipv4.dhcp-client-id=stable" only hashes the stable-id alone. The latter is a bug, we really want to generate per-host client-ids and will be fixed next. The point is, in various context we possibly anyway already include a per-host or a per-device token into the generation algorithm. However, the new specifiers are still useful, to declare this concept of a per-host or per-device token in the stable-id itself. While arguably "${HOST}" is (soon) anyway implicitly used everywhere, "${DEVICE}" is genuinely useful. Especially for the DHCPv4 client identifier which is supposed to differ between interfaces (according to RFC). While we don't do that by default with "ipv4.dhcp-client-id=stable", it is now possible. Note that the fact that the client-id by default is the same accross interfaces, is also not a common problem, because commonly profiles are restricted to one device via connection.interface-name. Now the user can create profiles that activate on multiple devices, and configurably use the same or different stable client-id.
-rw-r--r--clients/common/settings-docs.h.in2
-rw-r--r--libnm-core/nm-setting-connection.c35
-rw-r--r--src/devices/nm-device.c12
-rw-r--r--src/nm-core-utils.c52
-rw-r--r--src/nm-core-utils.h4
-rw-r--r--src/tests/test-general.c2
6 files changed, 84 insertions, 23 deletions
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
index 2896158157..cc306be1b1 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_("Token to generate stable IDs for the connection. 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 also the interface name of the activating connection and a per-host secret key is included into the address generation so that the same stable-id on different hosts/devices yields different addresses. If the value is unset, an ID unique for the connection is used. Specifying a stable-id allows multiple connections to generate the same addresses. Another use is to generate IDs at runtime via dynamic substitutions. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-boot, or every time. 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}\" to create a unique id for this connection that changes with every reboot. Note that two connections only use the same effective id if their stable-id is also identical before performing dynamic substitutions.")
+#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 with ipv6.addr-gen-mode=stable-privacy, also the device's name and a per-host key is included, so that different systems and interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${HOST}\", \"${DEVICE}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-host, 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 \"-\").")
diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c
index 8e6cb87c6e..d6b25a005f 100644
--- a/libnm-core/nm-setting-connection.c
+++ b/libnm-core/nm-setting-connection.c
@@ -1535,7 +1535,10 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
/**
* NMSettingConnection:stable-id:
*
- * Token to generate stable IDs for the connection.
+ * 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
@@ -1543,26 +1546,28 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
* and wifi.cloned-mac-address=stable. It is also used as DHCP client
* identifier with ipv4.dhcp-client-id=stable.
*
- * Note that also the interface name of the activating connection and a
- * per-host secret key is included into the address generation so that the
- * same stable-id on different hosts/devices yields different addresses.
- *
- * If the value is unset, an ID unique for the connection is used.
- * Specifying a stable-id allows multiple connections to generate the
- * same addresses. Another use is to generate IDs at runtime via
- * dynamic substitutions.
+ * Note that depending on the context where it is used, other parameters are
+ * also seeded into the generation algorithm. For example with
+ * ipv6.addr-gen-mode=stable-privacy, also the device's name and a per-host
+ * key is included, so that different systems and interfaces yield different
+ * addresses.
*
* The '$' character is treated special to perform dynamic substitutions
- * at runtime. Currently supported are "${CONNECTION}", "${BOOT}", "${RANDOM}".
- * These effectively create unique IDs per-connection, per-boot, or every time.
+ * at runtime. Currently supported are "${CONNECTION}", "${HOST}", "${DEVICE}",
+ * "${BOOT}", "${RANDOM}".
+ * These effectively create unique IDs per-connection, per-host, 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}" to create a unique id for
- * this connection that changes with every reboot.
+ * 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.
*
- * Note that two connections only use the same effective id if
- * their stable-id is also identical before performing dynamic substitutions.
+ * 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.
*
* Since: 1.4
**/
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index d26f23d0a0..5ad38d45ca 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -1177,8 +1177,10 @@ _get_stable_id (NMDevice *self,
uuid = nm_connection_get_uuid (connection);
stable_type = nm_utils_stable_id_parse (stable_id,
- uuid,
NULL,
+ nm_device_get_ip_iface (self),
+ NULL,
+ uuid,
&generated);
/* current_stable_id_type is a bitfield! */
@@ -1197,12 +1199,12 @@ _get_stable_id (NMDevice *self,
nm_assert (stable_type == NM_UTILS_STABLE_TYPE_RANDOM);
priv->current_stable_id = nm_str_realloc (nm_utils_stable_id_random ());
}
+
_LOGT (LOGD_DEVICE,
- "stable-id: type=%d, \"%s\""
- "%s%s%s",
+ "stable-id: type=%d, \"%s\"%s",
(int) priv->current_stable_id_type,
priv->current_stable_id,
- NM_PRINT_FMT_QUOTED (stable_type == NM_UTILS_STABLE_TYPE_GENERATED, " from \"", generated, "\"", ""));
+ stable_type == NM_UTILS_STABLE_TYPE_GENERATED ? " (generated)" : "");
}
*out_stable_type = priv->current_stable_id_type;
@@ -13499,6 +13501,8 @@ nm_device_spawn_iface_helper (NMDevice *self)
if (nm_logging_enabled (LOGL_DEBUG, LOGD_DEVICE)) {
char *tmp;
+ /* Beware, we may print here --stable-id, which may contain ${HOST} specifier,
+ * which essentially is the SHA1 sum of secret-key. */
tmp = g_strjoinv (" ", (char **) argv->pdata);
_LOGD (LOGD_DEVICE, "running '%s'", tmp);
g_free (tmp);
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index 50df2b5c2e..5e381cd314 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -2896,6 +2896,44 @@ nm_utils_secret_key_get (const guint8 **out_secret_key,
return secret_key->is_good;
}
+static gboolean
+_secret_key_get_opaque (guint32 salt /* number in host-order */,
+ char *out_hashed_key /* at least 41 bytes */)
+{
+ gboolean good_secret_key;
+ const guint8 *secret_key;
+ gsize key_len;
+ GChecksum *sum;
+ guint8 buf[20];
+ gsize buf_size;
+
+ /* returns the SHA1 sum of the secret-key in ASCII. Also, it includes
+ * a salt, so that one cannot obtain the secret-key from the hashed value. */
+
+ nm_assert (salt != 0);
+ nm_assert (out_hashed_key);
+
+ salt = htons (salt);
+
+ good_secret_key = nm_utils_secret_key_get (&secret_key, &key_len);
+
+ sum = g_checksum_new (G_CHECKSUM_SHA1);
+ g_checksum_update (sum, (const guchar *) &salt, sizeof (salt));
+ g_checksum_update (sum, (const guchar *) secret_key, key_len);
+
+ buf_size = sizeof (buf);
+ g_checksum_get_digest (sum, buf, &buf_size);
+ nm_assert (buf_size == sizeof (buf));
+
+ g_checksum_free (sum);
+
+ /* converting a buffer of 20 bytes to ascii (without delimiter) requires
+ * at least 41 bytes. @out_hashed_key must be this large. */
+ _nm_utils_bin2str_full (buf, sizeof (buf), '\0', FALSE, out_hashed_key);
+
+ return good_secret_key;
+}
+
/*****************************************************************************/
const char *
@@ -3181,12 +3219,15 @@ _stable_id_append (GString *str,
NMUtilsStableType
nm_utils_stable_id_parse (const char *stable_id,
- const char *uuid,
+ const char *hostid,
+ const char *deviceid,
const char *bootid,
+ const char *uuid,
char **out_generated)
{
gsize i, idx_start;
GString *str = NULL;
+ char hostid_buf[41];
g_return_val_if_fail (out_generated, NM_UTILS_STABLE_TYPE_RANDOM);
@@ -3257,6 +3298,15 @@ nm_utils_stable_id_parse (const char *stable_id,
_stable_id_append (str, uuid);
else if (CHECK_PREFIX ("${BOOT}"))
_stable_id_append (str, bootid ?: nm_utils_get_boot_id ());
+ else if (CHECK_PREFIX ("${HOST}")) {
+ if (!hostid) {
+ /* use an arbitrary, but fixed salt. */
+ _secret_key_get_opaque (336556219u, hostid_buf);
+ hostid = hostid_buf;
+ }
+ _stable_id_append (str, hostid);
+ } else if (CHECK_PREFIX ("${DEVICE}"))
+ _stable_id_append (str, deviceid);
else if (g_str_has_prefix (&stable_id[i], "${RANDOM}")) {
/* RANDOM makes not so much sense for cloned-mac-address
* as the result is simmilar to specyifing "cloned-mac-address=random".
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
index ed66a7f0c8..01bf9f1ba8 100644
--- a/src/nm-core-utils.h
+++ b/src/nm-core-utils.h
@@ -340,8 +340,10 @@ typedef enum {
} NMUtilsStableType;
NMUtilsStableType nm_utils_stable_id_parse (const char *stable_id,
- const char *uuid,
+ const char *hostid,
+ const char *deviceid,
const char *bootid,
+ const char *uuid,
char **out_generated);
char *nm_utils_stable_id_random (void);
diff --git a/src/tests/test-general.c b/src/tests/test-general.c
index 0d500c62e2..b52aea91ae 100644
--- a/src/tests/test-general.c
+++ b/src/tests/test-general.c
@@ -1621,7 +1621,7 @@ do_test_stable_id_parse (const char *stable_id,
else
g_assert (stable_id);
- stable_type = nm_utils_stable_id_parse (stable_id, "_CONNECTION", "_BOOT", &generated);
+ stable_type = nm_utils_stable_id_parse (stable_id, "_HOST", "_DEVICE", "_BOOT", "_CONNECTION", &generated);
g_assert_cmpint (expected_stable_type, ==, stable_type);