mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-07-22 02:35:25 +00:00
device: support dynamic "connection.stable-id" in form of text-substitution
Usecase: when connecting to a public Wi-Fi with MAC address randomization ("wifi.cloned-mac-address=random") you get on every re-connect a new IP address due to the changing MAC address. "wifi.cloned-mac-address=stable" is the solution for that. But that means, every time when reconnecting to this network, the same ID will be reused. We want an ID that is stable for a while, but at a later point a new ID should e generated when revisiting the Wi-Fi network. Extend the stable-id to become dynamic and support templates/substitutions. Currently supported is "${CONNECTION}", "${BOOT}" and "${RANDOM}". Any unrecognized pattern is treated verbaim/untranslated. "$$" is treated special to allow escaping the '$' character. This allows the user to still embed verbatim '$' characters with the guarantee that future versions of NetworkManager will still generate the same ID. Of course, a user could just avoid '$' in the stable-id unless using it for dynamic substitutions. Later we might want to add more recognized substitutions. For example, it could be useful to generate new IDs based on the current time. The ${} syntax is extendable to support arguments like "${PERIODIC:weekly}". Also allow "connection.stable-id" to be set as global default value. Previously that made no sense because the stable-id was static and is anyway strongly tied to the identity of the connection profile. Now, with dynamic stable-ids it gets much more useful to specify a global default. Note that pre-existing stable-ids don't change and still generate the same addresses -- unless they contain one of the new ${} patterns.
This commit is contained in:
parent
21ae09c1cc
commit
f0d40525df
|
@ -1432,13 +1432,32 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
|
|||
/**
|
||||
* NMSettingConnection:stable-id:
|
||||
*
|
||||
* This token to generate stable IDs for the connection. If unset,
|
||||
* the UUID will be used instead.
|
||||
* Token to generate stable IDs for the connection.
|
||||
*
|
||||
* The stable-id is used instead of the connection UUID 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.
|
||||
* 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. 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.
|
||||
* Specifing 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.
|
||||
*
|
||||
* Since: 1.4
|
||||
**/
|
||||
|
|
|
@ -717,8 +717,8 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class)
|
|||
* 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
|
||||
* identification and the network address as specified by RFC7217.
|
||||
* 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.
|
||||
|
|
|
@ -1150,8 +1150,8 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_wired_class)
|
|||
* "preserve" means not to touch the MAC address on activation.
|
||||
* "permanent" means to use the permanent hardware address of the device.
|
||||
* "random" creates a random MAC address on each connect.
|
||||
* "stable" creates a hashed MAC address based on connection.stable-id (or
|
||||
* the connection's UUID) and a machine dependent key.
|
||||
* "stable" creates a hashed MAC address based on connection.stable-id and a
|
||||
* machine dependent key.
|
||||
*
|
||||
* If unspecified, the value can be overwritten via global defaults, see manual
|
||||
* of NetworkManager.conf. If still unspecified, it defaults to "preserve"
|
||||
|
|
|
@ -1348,8 +1348,8 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_wireless_class)
|
|||
* "preserve" means not to touch the MAC address on activation.
|
||||
* "permanent" means to use the permanent hardware address of the device.
|
||||
* "random" creates a random MAC address on each connect.
|
||||
* "stable" creates a hashed MAC address based on connection.stable-id (or
|
||||
* the connection's UUID) and a machine dependent key.
|
||||
* "stable" creates a hashed MAC address based on connection.stable-id and a
|
||||
* machine dependent key.
|
||||
*
|
||||
* If unspecified, the value can be overwritten via global defaults, see manual
|
||||
* of NetworkManager.conf. If still unspecified, it defaults to "preserve"
|
||||
|
|
|
@ -600,6 +600,9 @@ ipv6.ip6-privacy=0
|
|||
<varlistentry>
|
||||
<term><varname>connection.lldp</varname></term>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>connection.stable-id</varname></term>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>ethernet.cloned-mac-address</varname></term>
|
||||
<listitem><para>If left unspecified, it defaults to "preserve".</para></listitem>
|
||||
|
|
|
@ -261,6 +261,9 @@ typedef struct _NMDevicePrivate {
|
|||
bool firmware_missing:1;
|
||||
bool nm_plugin_missing:1;
|
||||
bool hw_addr_perm_fake:1; /* whether the permanent HW address could not be read and is a fake */
|
||||
|
||||
NMUtilsStableType current_stable_id_type:3;
|
||||
|
||||
GHashTable * available_connections;
|
||||
char * hw_addr;
|
||||
char * hw_addr_perm;
|
||||
|
@ -310,6 +313,8 @@ typedef struct _NMDevicePrivate {
|
|||
guint32 dhcp_timeout;
|
||||
char * dhcp_anycast_address;
|
||||
|
||||
char * current_stable_id;
|
||||
|
||||
/* Proxy Configuration */
|
||||
NMProxyConfig *proxy_config;
|
||||
NMPacrunnerManager *pacrunner_manager;
|
||||
|
@ -663,25 +668,76 @@ _add_capabilities (NMDevice *self, NMDeviceCapabilities capabilities)
|
|||
/*****************************************************************************/
|
||||
|
||||
static const char *
|
||||
_get_stable_id (NMConnection *connection, NMUtilsStableType *out_stable_type)
|
||||
_get_stable_id (NMDevice *self,
|
||||
NMConnection *connection,
|
||||
NMUtilsStableType *out_stable_type)
|
||||
{
|
||||
NMSettingConnection *s_con;
|
||||
const char *stable_id;
|
||||
NMDevicePrivate *priv;
|
||||
|
||||
nm_assert (NM_IS_DEVICE (self));
|
||||
nm_assert (NM_IS_CONNECTION (connection));
|
||||
nm_assert (out_stable_type);
|
||||
|
||||
s_con = nm_connection_get_setting_connection (connection);
|
||||
g_return_val_if_fail (s_con, NULL);
|
||||
priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
stable_id = nm_setting_connection_get_stable_id (s_con);
|
||||
if (!stable_id) {
|
||||
*out_stable_type = NM_UTILS_STABLE_TYPE_UUID;
|
||||
return nm_connection_get_uuid (connection);
|
||||
/* we cache the generated stable ID for the time of an activation.
|
||||
*
|
||||
* The reason is, that we don't want the stable-id to change as long
|
||||
* as the device is active.
|
||||
*
|
||||
* Especially with ${RANDOM} stable-id we want to generate *one* configuration
|
||||
* for each activation. */
|
||||
if (G_UNLIKELY (!priv->current_stable_id)) {
|
||||
gs_free char *default_id = NULL;
|
||||
gs_free char *generated = NULL;
|
||||
NMUtilsStableType stable_type;
|
||||
NMSettingConnection *s_con;
|
||||
const char *stable_id;
|
||||
const char *uuid;
|
||||
|
||||
s_con = nm_connection_get_setting_connection (connection);
|
||||
|
||||
stable_id = nm_setting_connection_get_stable_id (s_con);
|
||||
|
||||
if (!stable_id) {
|
||||
default_id = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
|
||||
"connection.stable-id",
|
||||
self);
|
||||
stable_id = default_id;
|
||||
}
|
||||
|
||||
uuid = nm_connection_get_uuid (connection);
|
||||
|
||||
stable_type = nm_utils_stable_id_parse (stable_id,
|
||||
uuid,
|
||||
NULL,
|
||||
&generated);
|
||||
|
||||
/* current_stable_id_type is a bitfield! */
|
||||
nm_assert (stable_type <= (NMUtilsStableType) 0x2);
|
||||
nm_assert (stable_type + (NMUtilsStableType) 1 > (NMUtilsStableType) 0);
|
||||
priv->current_stable_id_type = stable_type;
|
||||
|
||||
if (stable_type == NM_UTILS_STABLE_TYPE_UUID)
|
||||
priv->current_stable_id = g_strdup (uuid);
|
||||
else if (stable_type == NM_UTILS_STABLE_TYPE_STABLE_ID)
|
||||
priv->current_stable_id = g_strdup (stable_id);
|
||||
else if (stable_type == NM_UTILS_STABLE_TYPE_GENERATED)
|
||||
priv->current_stable_id = nm_str_realloc (nm_utils_stable_id_generated_complete (generated));
|
||||
else {
|
||||
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",
|
||||
(int) priv->current_stable_id_type,
|
||||
priv->current_stable_id,
|
||||
NM_PRINT_FMT_QUOTED (stable_type == NM_UTILS_STABLE_TYPE_GENERATED, " from \"", generated, "\"", ""));
|
||||
}
|
||||
|
||||
*out_stable_type = NM_UTILS_STABLE_TYPE_STABLE_ID;
|
||||
return stable_id;
|
||||
*out_stable_type = priv->current_stable_id_type;
|
||||
return priv->current_stable_id;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -6438,7 +6494,7 @@ check_and_add_ipv6ll_addr (NMDevice *self)
|
|||
NMUtilsStableType stable_type;
|
||||
const char *stable_id;
|
||||
|
||||
stable_id = _get_stable_id (connection, &stable_type);
|
||||
stable_id = _get_stable_id (self, connection, &stable_type);
|
||||
if ( !stable_id
|
||||
|| !nm_utils_ipv6_addr_set_stable_privacy (stable_type,
|
||||
&lladdr,
|
||||
|
@ -6843,7 +6899,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
|
|||
s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection));
|
||||
g_assert (s_ip6);
|
||||
|
||||
stable_id = _get_stable_id (connection, &stable_type);
|
||||
stable_id = _get_stable_id (self, connection, &stable_type);
|
||||
if (stable_id) {
|
||||
priv->ndisc = nm_lndp_ndisc_new (NM_PLATFORM_GET,
|
||||
nm_device_get_ip_ifindex (self),
|
||||
|
@ -11375,7 +11431,7 @@ nm_device_spawn_iface_helper (NMDevice *self)
|
|||
g_ptr_array_add (argv, g_strdup ("--uuid"));
|
||||
g_ptr_array_add (argv, g_strdup (nm_connection_get_uuid (connection)));
|
||||
|
||||
stable_id = _get_stable_id (connection, &stable_type);
|
||||
stable_id = _get_stable_id (self, connection, &stable_type);
|
||||
if (stable_id && stable_type != NM_UTILS_STABLE_TYPE_UUID) {
|
||||
g_ptr_array_add (argv, g_strdup ("--stable-id"));
|
||||
g_ptr_array_add (argv, g_strdup_printf ("%d %s", (int) stable_type, stable_id));
|
||||
|
@ -11670,6 +11726,11 @@ _set_state_full (NMDevice *self,
|
|||
if (state >= NM_DEVICE_STATE_DISCONNECTED && old_state < NM_DEVICE_STATE_DISCONNECTED)
|
||||
nm_device_recheck_available_connections (self);
|
||||
|
||||
if (state <= NM_DEVICE_STATE_DISCONNECTED || state > NM_DEVICE_STATE_DEACTIVATING) {
|
||||
if (nm_clear_g_free (&priv->current_stable_id))
|
||||
_LOGT (LOGD_DEVICE, "stable-id: clear");
|
||||
}
|
||||
|
||||
/* Handle the new state here; but anything that could trigger
|
||||
* another state change should be done below.
|
||||
*/
|
||||
|
@ -12544,7 +12605,7 @@ nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
stable_id = _get_stable_id (connection, &stable_type);
|
||||
stable_id = _get_stable_id (self, connection, &stable_type);
|
||||
if (stable_id) {
|
||||
hw_addr_generated = nm_utils_hw_addr_gen_stable_eth (stable_type, stable_id,
|
||||
nm_device_get_ip_iface (self),
|
||||
|
@ -12933,6 +12994,7 @@ finalize (GObject *object)
|
|||
g_free (priv->type_desc);
|
||||
g_free (priv->type_description);
|
||||
g_free (priv->dhcp_anycast_address);
|
||||
g_free (priv->current_stable_id);
|
||||
|
||||
g_hash_table_unref (priv->ip6_saved_properties);
|
||||
g_hash_table_unref (priv->available_connections);
|
||||
|
|
|
@ -1176,7 +1176,7 @@ nm_ndisc_class_init (NMNDiscClass *klass)
|
|||
G_PARAM_STATIC_STRINGS);
|
||||
obj_properties[PROP_STABLE_TYPE] =
|
||||
g_param_spec_int (NM_NDISC_STABLE_TYPE, "", "",
|
||||
NM_UTILS_STABLE_TYPE_UUID, NM_UTILS_STABLE_TYPE_STABLE_ID, NM_UTILS_STABLE_TYPE_UUID,
|
||||
NM_UTILS_STABLE_TYPE_UUID, NM_UTILS_STABLE_TYPE_RANDOM, NM_UTILS_STABLE_TYPE_UUID,
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
|
|
@ -3267,6 +3267,186 @@ nm_utils_inet6_interface_identifier_to_token (NMUtilsIPv6IfaceId iid, char *buf)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
char *
|
||||
nm_utils_stable_id_random (void)
|
||||
{
|
||||
char buf[15];
|
||||
|
||||
if (nm_utils_read_urandom (buf, sizeof (buf)) < 0)
|
||||
g_return_val_if_reached (nm_utils_uuid_generate ());
|
||||
return g_base64_encode ((guchar *) buf, sizeof (buf));
|
||||
}
|
||||
|
||||
char *
|
||||
nm_utils_stable_id_generated_complete (const char *stable_id_generated)
|
||||
{
|
||||
guint8 buf[20];
|
||||
GChecksum *sum;
|
||||
gsize buf_size;
|
||||
char *base64;
|
||||
|
||||
/* for NM_UTILS_STABLE_TYPE_GENERATED we genererate a possibly long string
|
||||
* by doing text-substitutions in nm_utils_stable_id_parse().
|
||||
*
|
||||
* Let's shorten the (possibly) long stable_id to something more compact. */
|
||||
|
||||
g_return_val_if_fail (stable_id_generated, NULL);
|
||||
|
||||
sum = g_checksum_new (G_CHECKSUM_SHA1);
|
||||
nm_assert (sum);
|
||||
|
||||
g_checksum_update (sum, (guchar *) stable_id_generated, strlen (stable_id_generated));
|
||||
|
||||
buf_size = sizeof (buf);
|
||||
g_checksum_get_digest (sum, buf, &buf_size);
|
||||
nm_assert (buf_size == sizeof (buf));
|
||||
|
||||
g_checksum_free (sum);
|
||||
|
||||
/* we don't care to use the sha1 sum in common hex representation.
|
||||
* Use instead base64, it's 27 chars (stripping the padding) vs.
|
||||
* 40. */
|
||||
|
||||
base64 = g_base64_encode ((guchar *) buf, sizeof (buf));
|
||||
nm_assert (strlen (base64) == 28);
|
||||
nm_assert (base64[27] == '=');
|
||||
|
||||
base64[27] = '\0';
|
||||
return base64;
|
||||
}
|
||||
|
||||
static void
|
||||
_stable_id_append (GString *str,
|
||||
const char *substitution)
|
||||
{
|
||||
if (!substitution)
|
||||
substitution = "";
|
||||
g_string_append_printf (str, "=%zu{%s}", strlen (substitution), substitution);
|
||||
}
|
||||
|
||||
NMUtilsStableType
|
||||
nm_utils_stable_id_parse (const char *stable_id,
|
||||
const char *uuid,
|
||||
const char *bootid,
|
||||
char **out_generated)
|
||||
{
|
||||
gsize i, idx_start;
|
||||
GString *str = NULL;
|
||||
|
||||
g_return_val_if_fail (out_generated, NM_UTILS_STABLE_TYPE_RANDOM);
|
||||
|
||||
if (!stable_id) {
|
||||
out_generated = NULL;
|
||||
return NM_UTILS_STABLE_TYPE_UUID;
|
||||
}
|
||||
|
||||
/* the stable-id allows for some dynamic by performing text-substitutions
|
||||
* of ${...} patterns.
|
||||
*
|
||||
* At first, it looks a bit like bash parameter substitution.
|
||||
* In contrast however, the process is unambigious so that the resulting
|
||||
* effective id differs if:
|
||||
* - the original, untranslated stable-id differs
|
||||
* - or any of the subsitutions differs.
|
||||
*
|
||||
* The reason for that is, for example if you specify "${CONNECTION}" in the
|
||||
* stable-id, then the resulting ID should be always(!) unique for this connection.
|
||||
* There should be no way another connection could specify any stable-id that results
|
||||
* in the same addresses to be generated (aside hash collisions).
|
||||
*
|
||||
*
|
||||
* For example: say you have a connection with UUID
|
||||
* "123e4567-e89b-12d3-a456-426655440000" which happens also to be
|
||||
* the current boot-id.
|
||||
* Then:
|
||||
* (1) connection.stable-id = <NULL>
|
||||
* (2) connection.stable-id = "123e4567-e89b-12d3-a456-426655440000"
|
||||
* (3) connection.stable-id = "${CONNECTION}"
|
||||
* (3) connection.stable-id = "${BOOT}"
|
||||
* will all generate different addresses, although in one way or the
|
||||
* other, they all mangle the uuid "123e4567-e89b-12d3-a456-426655440000".
|
||||
*
|
||||
* For example, with stable-id="${FOO}${BAR}" the substitutions
|
||||
* - FOO="ab", BAR="c"
|
||||
* - FOO="a", BAR="bc"
|
||||
* should give a different effective id.
|
||||
*
|
||||
* For example, with FOO="x" and BAR="x", the stable-ids
|
||||
* - "${FOO}${BAR}"
|
||||
* - "${BAR}${FOO}"
|
||||
* should give a different effective id.
|
||||
*/
|
||||
|
||||
idx_start = 0;
|
||||
for (i = 0; stable_id[i]; ) {
|
||||
if (stable_id[i] != '$') {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#define CHECK_PREFIX(prefix) \
|
||||
({ \
|
||||
gboolean _match = FALSE; \
|
||||
\
|
||||
if (g_str_has_prefix (&stable_id[i], ""prefix"")) { \
|
||||
_match = TRUE; \
|
||||
if (!str) \
|
||||
str = g_string_sized_new (256); \
|
||||
i += NM_STRLEN (prefix); \
|
||||
g_string_append_len (str, &(stable_id)[idx_start], i - idx_start); \
|
||||
idx_start = i; \
|
||||
} \
|
||||
_match; \
|
||||
})
|
||||
if (CHECK_PREFIX ("${CONNECTION}"))
|
||||
_stable_id_append (str, uuid);
|
||||
else if (CHECK_PREFIX ("${BOOT}"))
|
||||
_stable_id_append (str, bootid ?: nm_utils_get_boot_id ());
|
||||
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 specifing "cloned-mac-address=random".
|
||||
* It makes however sense for RFC 7217 Stable Privacy IPv6 addresses
|
||||
* where this is effectively the only way to generate a different
|
||||
* (random) host identifier for each connect.
|
||||
*
|
||||
* With RANDOM, the user can switch the lifetime of the
|
||||
* generated cloned-mac-address and IPv6 host identifier
|
||||
* by toggeling only the stable-id property of the connection.
|
||||
* With RANDOM being the most short-lived, ~non-stable~ variant.
|
||||
*/
|
||||
if (str)
|
||||
g_string_free (str, TRUE);
|
||||
*out_generated = NULL;
|
||||
return NM_UTILS_STABLE_TYPE_RANDOM;
|
||||
} else {
|
||||
/* The text following the '$' is not recognized as valid
|
||||
* substitution pattern. Treat it verbatim. */
|
||||
i++;
|
||||
|
||||
/* Note that using unrecognized substitution patterns might
|
||||
* yield different results with future versions. Avoid that,
|
||||
* by not using '$' (except for actual substitutions) or escape
|
||||
* it as "$$" (which is guaranteed to be treated verbatim
|
||||
* in future). */
|
||||
if (stable_id[i] == '$')
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#undef CHECK_PREFIX
|
||||
|
||||
if (!str) {
|
||||
*out_generated = NULL;
|
||||
return NM_UTILS_STABLE_TYPE_STABLE_ID;
|
||||
}
|
||||
|
||||
if (idx_start < i)
|
||||
g_string_append_len (str, &stable_id[idx_start], i - idx_start);
|
||||
*out_generated = g_string_free (str, FALSE);
|
||||
return NM_UTILS_STABLE_TYPE_GENERATED;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
_set_stable_privacy (NMUtilsStableType stable_type,
|
||||
struct in6_addr *addr,
|
||||
|
|
|
@ -369,10 +369,19 @@ typedef enum {
|
|||
* Also note, if we ever allocate ID 255, we must take care
|
||||
* that nm_utils_ipv6_addr_set_stable_privacy() extends the
|
||||
* uint8 encoding of this value. */
|
||||
NM_UTILS_STABLE_TYPE_UUID = 0,
|
||||
NM_UTILS_STABLE_TYPE_UUID = 0,
|
||||
NM_UTILS_STABLE_TYPE_STABLE_ID = 1,
|
||||
NM_UTILS_STABLE_TYPE_GENERATED = 2,
|
||||
NM_UTILS_STABLE_TYPE_RANDOM = 3,
|
||||
} NMUtilsStableType;
|
||||
|
||||
NMUtilsStableType nm_utils_stable_id_parse (const char *stable_id,
|
||||
const char *uuid,
|
||||
const char *bootid,
|
||||
char **out_generated);
|
||||
|
||||
char *nm_utils_stable_id_random (void);
|
||||
char *nm_utils_stable_id_generated_complete (const char *msg);
|
||||
|
||||
gboolean nm_utils_ipv6_addr_set_stable_privacy_impl (NMUtilsStableType stable_type,
|
||||
struct in6_addr *addr,
|
||||
|
|
|
@ -1481,6 +1481,89 @@ test_reverse_dns_ip6 (void)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
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;
|
||||
|
||||
if (expected_stable_type == NM_UTILS_STABLE_TYPE_GENERATED)
|
||||
g_assert (expected_generated);
|
||||
else
|
||||
g_assert (!expected_generated);
|
||||
|
||||
if (expected_stable_type == NM_UTILS_STABLE_TYPE_UUID)
|
||||
g_assert (!stable_id);
|
||||
else
|
||||
g_assert (stable_id);
|
||||
|
||||
stable_type = nm_utils_stable_id_parse (stable_id, "_CONNECTION", "_BOOT", &generated);
|
||||
|
||||
g_assert_cmpint (expected_stable_type, ==, stable_type);
|
||||
|
||||
if (stable_type == NM_UTILS_STABLE_TYPE_GENERATED) {
|
||||
g_assert_cmpstr (expected_generated, ==, generated);
|
||||
g_assert (generated);
|
||||
} else
|
||||
g_assert (!generated);
|
||||
}
|
||||
|
||||
static void
|
||||
test_stable_id_parse (void)
|
||||
{
|
||||
#define _parse_stable_id(stable_id) do_test_stable_id_parse (""stable_id"", NM_UTILS_STABLE_TYPE_STABLE_ID, NULL)
|
||||
#define _parse_generated(stable_id, expected_generated) do_test_stable_id_parse (""stable_id"", NM_UTILS_STABLE_TYPE_GENERATED, ""expected_generated"")
|
||||
#define _parse_random(stable_id) do_test_stable_id_parse (""stable_id"", NM_UTILS_STABLE_TYPE_RANDOM, NULL)
|
||||
do_test_stable_id_parse (NULL, NM_UTILS_STABLE_TYPE_UUID, NULL);
|
||||
_parse_stable_id ("");
|
||||
_parse_stable_id ("a");
|
||||
_parse_stable_id ("a$");
|
||||
_parse_stable_id ("a$x");
|
||||
_parse_stable_id (" ${a$x");
|
||||
_parse_stable_id ("${");
|
||||
_parse_stable_id ("${=");
|
||||
_parse_stable_id ("${a");
|
||||
_parse_stable_id ("${a$x");
|
||||
_parse_stable_id ("a$$");
|
||||
_parse_stable_id ("a$$x");
|
||||
_parse_stable_id ("a$${CONNECTION}");
|
||||
_parse_stable_id ("a$${CONNECTION}x");
|
||||
_parse_generated ("${CONNECTION}", "${CONNECTION}=11{_CONNECTION}");
|
||||
_parse_generated ("${${CONNECTION}", "${${CONNECTION}=11{_CONNECTION}");
|
||||
_parse_generated ("${CONNECTION}x", "${CONNECTION}=11{_CONNECTION}x");
|
||||
_parse_generated ("x${CONNECTION}", "x${CONNECTION}=11{_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}");
|
||||
_parse_generated ("xX${BOOT}yY${CONNECTION}zZ", "xX${BOOT}=5{_BOOT}yY${CONNECTION}=11{_CONNECTION}zZ");
|
||||
_parse_random ("${RANDOM}");
|
||||
_parse_random (" ${RANDOM}");
|
||||
_parse_random ("${BOOT}${RANDOM}");
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_stable_id_generated_complete (void)
|
||||
{
|
||||
#define ASSERT(str, expected) \
|
||||
G_STMT_START { \
|
||||
gs_free char *_s = NULL; \
|
||||
\
|
||||
_s = nm_utils_stable_id_generated_complete ((str)); \
|
||||
g_assert_cmpstr ((expected), ==, _s); \
|
||||
} G_STMT_END
|
||||
|
||||
ASSERT ("", "2jmj7l5rSw0yVb/vlWAYkK/YBwk");
|
||||
ASSERT ("a", "hvfkN/qlp/zhXR3cuerq6jd2Z7g");
|
||||
ASSERT ("password", "W6ph5Mm5Pz8GgiULbPgzG37mj9g");
|
||||
#undef ASSERT
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMTST_DEFINE ();
|
||||
|
||||
int
|
||||
|
@ -1518,6 +1601,9 @@ main (int argc, char **argv)
|
|||
g_test_add_func ("/general/reverse_dns/ip4", test_reverse_dns_ip4);
|
||||
g_test_add_func ("/general/reverse_dns/ip6", test_reverse_dns_ip6);
|
||||
|
||||
g_test_add_func ("/general/stable-id/parse", test_stable_id_parse);
|
||||
g_test_add_func ("/general/stable-id/generated-complete", test_stable_id_generated_complete);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue