device: extend MAC address handling including randomization for ethernet and wifi

Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.

"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.

"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a6.

"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".

On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.

There is some overlap with the "wifi.mac-address-randomization" setting.

https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
This commit is contained in:
Thomas Haller
2016-05-24 15:57:16 +02:00
parent 1a6d6d56e6
commit 8eed67122c
27 changed files with 792 additions and 124 deletions

View File

@@ -24,6 +24,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include "nm-common-macros.h"
#include "utils.h" #include "utils.h"
#include "common.h" #include "common.h"
#include "nm-vpn-helpers.h" #include "nm-vpn-helpers.h"
@@ -2889,11 +2890,12 @@ nmc_property_set_ssid (NMSetting *setting, const char *prop, const char *val, GE
} }
static gboolean static gboolean
nmc_property_set_mac (NMSetting *setting, const char *prop, const char *val, GError **error) _property_set_mac (NMSetting *setting, const char *prop, const char *val, gboolean cloned_mac_addr, GError **error)
{ {
g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (!nm_utils_hwaddr_valid (val, ETH_ALEN)) { if ( (!cloned_mac_addr || !NM_CLONED_MAC_IS_SPECIAL (val))
&& !nm_utils_hwaddr_valid (val, ETH_ALEN)) {
g_set_error (error, 1, 0, _("'%s' is not a valid Ethernet MAC"), val); g_set_error (error, 1, 0, _("'%s' is not a valid Ethernet MAC"), val);
return FALSE; return FALSE;
} }
@@ -2902,6 +2904,18 @@ nmc_property_set_mac (NMSetting *setting, const char *prop, const char *val, GEr
return TRUE; return TRUE;
} }
static gboolean
nmc_property_set_mac (NMSetting *setting, const char *prop, const char *val, GError **error)
{
return _property_set_mac (setting, prop, val, FALSE, error);
}
static gboolean
nmc_property_set_mac_cloned (NMSetting *setting, const char *prop, const char *val, GError **error)
{
return _property_set_mac (setting, prop, val, TRUE, error);
}
static gboolean static gboolean
nmc_property_set_mtu (NMSetting *setting, const char *prop, const char *val, GError **error) nmc_property_set_mtu (NMSetting *setting, const char *prop, const char *val, GError **error)
{ {
@@ -7198,7 +7212,7 @@ nmc_properties_init (void)
NULL); NULL);
nmc_add_prop_funcs (GLUE (WIRED, CLONED_MAC_ADDRESS), nmc_add_prop_funcs (GLUE (WIRED, CLONED_MAC_ADDRESS),
nmc_property_wired_get_cloned_mac_address, nmc_property_wired_get_cloned_mac_address,
nmc_property_set_mac, nmc_property_set_mac_cloned,
NULL, NULL,
NULL, NULL,
NULL, NULL,
@@ -7316,7 +7330,7 @@ nmc_properties_init (void)
NULL); NULL);
nmc_add_prop_funcs (GLUE (WIRELESS, CLONED_MAC_ADDRESS), nmc_add_prop_funcs (GLUE (WIRELESS, CLONED_MAC_ADDRESS),
nmc_property_wireless_get_cloned_mac_address, nmc_property_wireless_get_cloned_mac_address,
nmc_property_set_mac, nmc_property_set_mac_cloned,
NULL, NULL,
NULL, NULL,
NULL, NULL,

View File

@@ -28,11 +28,13 @@
#include "nm-default.h" #include "nm-default.h"
#include "nmt-mac-entry.h"
#include <string.h> #include <string.h>
#include "NetworkManager.h" #include "NetworkManager.h"
#include "nm-common-macros.h"
#include "nmt-mac-entry.h"
G_DEFINE_TYPE (NmtMacEntry, nmt_mac_entry, NMT_TYPE_NEWT_ENTRY) G_DEFINE_TYPE (NmtMacEntry, nmt_mac_entry, NMT_TYPE_NEWT_ENTRY)
@@ -41,6 +43,7 @@ G_DEFINE_TYPE (NmtMacEntry, nmt_mac_entry, NMT_TYPE_NEWT_ENTRY)
typedef struct { typedef struct {
int mac_length; int mac_length;
int mac_str_length; int mac_str_length;
NmtMacEntryType entry_type;
} NmtMacEntryPrivate; } NmtMacEntryPrivate;
@@ -48,6 +51,7 @@ enum {
PROP_0, PROP_0,
PROP_MAC_LENGTH, PROP_MAC_LENGTH,
PROP_MAC_ADDRESS, PROP_MAC_ADDRESS,
PROP_ENTRY_TYPE,
LAST_PROP LAST_PROP
}; };
@@ -57,6 +61,7 @@ enum {
* @width: the width in characters of the entry * @width: the width in characters of the entry
* @mac_length: the length in bytes of the hardware address * @mac_length: the length in bytes of the hardware address
* (either %ETH_ALEN or %INFINIBAND_ALEN) * (either %ETH_ALEN or %INFINIBAND_ALEN)
* @entry_type: the type of the entry.
* *
* Creates a new #NmtMacEntry. * Creates a new #NmtMacEntry.
* *
@@ -64,11 +69,13 @@ enum {
*/ */
NmtNewtWidget * NmtNewtWidget *
nmt_mac_entry_new (int width, nmt_mac_entry_new (int width,
int mac_length) int mac_length,
NmtMacEntryType entry_type)
{ {
return g_object_new (NMT_TYPE_MAC_ENTRY, return g_object_new (NMT_TYPE_MAC_ENTRY,
"width", width, "width", width,
"mac-length", mac_length, "mac-length", mac_length,
"entry-type", (int) entry_type,
NULL); NULL);
} }
@@ -81,6 +88,9 @@ mac_filter (NmtNewtEntry *entry,
{ {
NmtMacEntryPrivate *priv = NMT_MAC_ENTRY_GET_PRIVATE (entry); NmtMacEntryPrivate *priv = NMT_MAC_ENTRY_GET_PRIVATE (entry);
if (priv->entry_type != NMT_MAC_ENTRY_TYPE_MAC)
return TRUE;
if (position >= priv->mac_str_length) if (position >= priv->mac_str_length)
return FALSE; return FALSE;
@@ -98,6 +108,11 @@ mac_validator (NmtNewtEntry *entry,
if (!*text) if (!*text)
return TRUE; return TRUE;
if (priv->entry_type == NMT_MAC_ENTRY_TYPE_CLONED) {
if (NM_CLONED_MAC_IS_SPECIAL (text))
return TRUE;
}
p = text; p = text;
while ( g_ascii_isxdigit (p[0]) while ( g_ascii_isxdigit (p[0])
&& g_ascii_isxdigit (p[1]) && g_ascii_isxdigit (p[1])
@@ -112,7 +127,9 @@ mac_validator (NmtNewtEntry *entry,
if (!*p) if (!*p)
return (p - text == priv->mac_str_length); return (p - text == priv->mac_str_length);
if (g_ascii_isxdigit (p[0]) && !p[1]) { if ( g_ascii_isxdigit (p[0])
&& !p[1]
&& p - text < priv->mac_str_length) {
char *fixed = g_strdup_printf ("%.*s:%c", (int)(p - text), text, *p); char *fixed = g_strdup_printf ("%.*s:%c", (int)(p - text), text, *p);
nmt_newt_entry_set_text (entry, fixed); nmt_newt_entry_set_text (entry, fixed);
@@ -161,6 +178,10 @@ nmt_mac_entry_set_property (GObject *object,
case PROP_MAC_ADDRESS: case PROP_MAC_ADDRESS:
nmt_newt_entry_set_text (NMT_NEWT_ENTRY (object), g_value_get_string (value)); nmt_newt_entry_set_text (NMT_NEWT_ENTRY (object), g_value_get_string (value));
break; break;
case PROP_ENTRY_TYPE:
/* construct-only */
priv->entry_type = g_value_get_int (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@@ -182,6 +203,9 @@ nmt_mac_entry_get_property (GObject *object,
case PROP_MAC_ADDRESS: case PROP_MAC_ADDRESS:
g_value_set_string (value, nmt_newt_entry_get_text (NMT_NEWT_ENTRY (object))); g_value_set_string (value, nmt_newt_entry_get_text (NMT_NEWT_ENTRY (object)));
break; break;
case PROP_ENTRY_TYPE:
g_value_set_int (value, priv->entry_type);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@@ -224,4 +248,17 @@ nmt_mac_entry_class_init (NmtMacEntryClass *entry_class)
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
/**
* NmtMacEntry:entry-type:
*
* The type of the #NmtMacEntry. Can be either used for plain
* MAC addresses or for the extended format for cloned MAC addresses.
*/
g_object_class_install_property
(object_class, PROP_ENTRY_TYPE,
g_param_spec_int ("entry-type", "", "",
NMT_MAC_ENTRY_TYPE_MAC, NMT_MAC_ENTRY_TYPE_CLONED, NMT_MAC_ENTRY_TYPE_MAC,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
} }

View File

@@ -25,6 +25,11 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef enum { /*< skip >*/
NMT_MAC_ENTRY_TYPE_MAC,
NMT_MAC_ENTRY_TYPE_CLONED,
} NmtMacEntryType;
#define NMT_TYPE_MAC_ENTRY (nmt_mac_entry_get_type ()) #define NMT_TYPE_MAC_ENTRY (nmt_mac_entry_get_type ())
#define NMT_MAC_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_MAC_ENTRY, NmtMacEntry)) #define NMT_MAC_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_MAC_ENTRY, NmtMacEntry))
#define NMT_MAC_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_MAC_ENTRY, NmtMacEntryClass)) #define NMT_MAC_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_MAC_ENTRY, NmtMacEntryClass))
@@ -45,7 +50,8 @@ typedef struct {
GType nmt_mac_entry_get_type (void); GType nmt_mac_entry_get_type (void);
NmtNewtWidget *nmt_mac_entry_new (int width, NmtNewtWidget *nmt_mac_entry_new (int width,
int mac_length); int mac_length,
NmtMacEntryType type);
G_END_DECLS G_END_DECLS

View File

@@ -70,7 +70,7 @@ nmt_page_ethernet_constructed (GObject *object)
section = nmt_editor_section_new (_("ETHERNET"), NULL, FALSE); section = nmt_editor_section_new (_("ETHERNET"), NULL, FALSE);
grid = nmt_editor_section_get_body (section); grid = nmt_editor_section_get_body (section);
widget = nmt_mac_entry_new (40, ETH_ALEN); widget = nmt_mac_entry_new (40, ETH_ALEN, NMT_MAC_ENTRY_TYPE_CLONED);
g_object_bind_property (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, g_object_bind_property (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
widget, "mac-address", widget, "mac-address",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);

View File

@@ -115,7 +115,7 @@ nmt_page_vlan_constructed (GObject *object)
nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL);
widget = nmt_mac_entry_new (40, ETH_ALEN); widget = nmt_mac_entry_new (40, ETH_ALEN, NMT_MAC_ENTRY_TYPE_CLONED);
g_object_bind_property (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, g_object_bind_property (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
widget, "mac-address", widget, "mac-address",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);

View File

@@ -351,13 +351,13 @@ nmt_page_wifi_constructed (GObject *object)
nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL);
widget = nmt_mac_entry_new (40, ETH_ALEN); widget = nmt_mac_entry_new (40, ETH_ALEN, NMT_MAC_ENTRY_TYPE_MAC);
g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_BSSID, g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_BSSID,
widget, "mac-address", widget, "mac-address",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
nmt_editor_grid_append (grid, _("BSSID"), widget, NULL); nmt_editor_grid_append (grid, _("BSSID"), widget, NULL);
widget = nmt_mac_entry_new (40, ETH_ALEN); widget = nmt_mac_entry_new (40, ETH_ALEN, NMT_MAC_ENTRY_TYPE_CLONED);
g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS,
widget, "mac-address", widget, "mac-address",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);

View File

@@ -31,6 +31,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <string.h> #include <string.h>
#include "nm-common-macros.h"
#include "nm-core-internal.h" #include "nm-core-internal.h"
#include "nm-keyfile-utils.h" #include "nm-keyfile-utils.h"
@@ -581,19 +582,28 @@ ip6_addr_gen_mode_parser (KeyfileReaderInfo *info, NMSetting *setting, const cha
} }
static void static void
mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key, gsize enforce_length) mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key, gsize enforce_length, gboolean cloned_mac_addr)
{ {
const char *setting_name = nm_setting_get_name (setting); const char *setting_name = nm_setting_get_name (setting);
char *tmp_string = NULL, *p, *mac_str; gs_free char *tmp_string = NULL;
gint *tmp_list; const char *p, *mac_str;
GByteArray *array = NULL; gs_free guint8 *buf_arr = NULL;
guint buf_len;
gsize length; gsize length;
p = tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL); tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
if ( cloned_mac_addr
&& NM_CLONED_MAC_IS_SPECIAL (tmp_string)) {
mac_str = tmp_string;
goto out;
}
if (tmp_string && tmp_string[0]) { if (tmp_string && tmp_string[0]) {
/* Look for enough ':' characters to signify a MAC address */ /* Look for enough ':' characters to signify a MAC address */
guint i = 0; guint i = 0;
p = tmp_string;
while (*p) { while (*p) {
if (*p == ':') if (*p == ':')
i++; i++;
@@ -602,23 +612,24 @@ mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key
if (enforce_length == 0 || enforce_length == i+1) { if (enforce_length == 0 || enforce_length == i+1) {
/* If we found enough it's probably a string-format MAC address */ /* If we found enough it's probably a string-format MAC address */
array = g_byte_array_sized_new (i+1); buf_len = i + 1;
g_byte_array_set_size (array, i+1); buf_arr = g_new (guint8, buf_len);
if (!nm_utils_hwaddr_aton (tmp_string, array->data, array->len)) { if (!nm_utils_hwaddr_aton (tmp_string, buf_arr, buf_len))
g_byte_array_unref (array); g_clear_pointer (&buf_arr, g_free);
array = NULL;
}
} }
} }
g_free (tmp_string); g_clear_pointer (&tmp_string, g_free);
if (!buf_arr) {
gs_free int *tmp_list = NULL;
if (array == NULL) {
/* Old format; list of ints */ /* Old format; list of ints */
tmp_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &length, NULL); tmp_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &length, NULL);
if (length > 0 && (enforce_length == 0 || enforce_length == length)) { if (length > 0 && (enforce_length == 0 || enforce_length == length)) {
gsize i; gsize i;
array = g_byte_array_sized_new (length); buf_len = length;
buf_arr = g_new (guint8, buf_len);
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
int val = tmp_list[i]; int val = tmp_list[i];
const guint8 v = (guint8) (val & 0xFF); const guint8 v = (guint8) (val & 0xFF);
@@ -627,38 +638,42 @@ mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN, handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
_("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"), _("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"),
val); val);
g_byte_array_free (array, TRUE);
g_free (tmp_list);
return; return;
} }
g_byte_array_append (array, &v, 1); buf_arr[i] = v;
} }
} }
g_free (tmp_list);
} }
if (!array) { if (!buf_arr) {
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN, handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
_("ignoring invalid MAC address")); _("ignoring invalid MAC address"));
return; return;
} }
mac_str = nm_utils_hwaddr_ntoa (array->data, array->len); tmp_string = nm_utils_hwaddr_ntoa (buf_arr, buf_len);
mac_str = tmp_string;
out:
g_object_set (setting, key, mac_str, NULL); g_object_set (setting, key, mac_str, NULL);
g_free (mac_str);
g_byte_array_free (array, TRUE);
} }
static void static void
mac_address_parser_ETHER (KeyfileReaderInfo *info, NMSetting *setting, const char *key) mac_address_parser_ETHER (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{ {
mac_address_parser (info, setting, key, ETH_ALEN); mac_address_parser (info, setting, key, ETH_ALEN, FALSE);
}
static void
mac_address_parser_ETHER_cloned (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{
mac_address_parser (info, setting, key, ETH_ALEN, TRUE);
} }
static void static void
mac_address_parser_INFINIBAND (KeyfileReaderInfo *info, NMSetting *setting, const char *key) mac_address_parser_INFINIBAND (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{ {
mac_address_parser (info, setting, key, INFINIBAND_ALEN); mac_address_parser (info, setting, key, INFINIBAND_ALEN, FALSE);
} }
static void static void
@@ -1209,7 +1224,7 @@ static KeyParser key_parsers[] = {
{ NM_SETTING_WIRED_SETTING_NAME, { NM_SETTING_WIRED_SETTING_NAME,
NM_SETTING_WIRED_CLONED_MAC_ADDRESS, NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
TRUE, TRUE,
mac_address_parser_ETHER }, mac_address_parser_ETHER_cloned },
{ NM_SETTING_WIRELESS_SETTING_NAME, { NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_WIRELESS_MAC_ADDRESS, NM_SETTING_WIRELESS_MAC_ADDRESS,
TRUE, TRUE,
@@ -1217,7 +1232,7 @@ static KeyParser key_parsers[] = {
{ NM_SETTING_WIRELESS_SETTING_NAME, { NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS,
TRUE, TRUE,
mac_address_parser_ETHER }, mac_address_parser_ETHER_cloned },
{ NM_SETTING_WIRELESS_SETTING_NAME, { NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_WIRELESS_BSSID, NM_SETTING_WIRELESS_BSSID,
TRUE, TRUE,

View File

@@ -1415,6 +1415,8 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
* *
* The stable-id is used instead of the connection UUID for generating * The stable-id is used instead of the connection UUID for generating
* IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. * 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.
* *
* Since: 1.4 * Since: 1.4
**/ **/

View File

@@ -28,6 +28,7 @@
#include <net/ethernet.h> #include <net/ethernet.h>
#include "nm-utils.h" #include "nm-utils.h"
#include "nm-common-macros.h"
#include "nm-utils-private.h" #include "nm-utils-private.h"
#include "nm-setting-private.h" #include "nm-setting-private.h"
@@ -692,7 +693,9 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
} }
} }
if (priv->cloned_mac_address && !nm_utils_hwaddr_valid (priv->cloned_mac_address, ETH_ALEN)) { if ( priv->cloned_mac_address
&& !NM_CLONED_MAC_IS_SPECIAL (priv->cloned_mac_address)
&& !nm_utils_hwaddr_valid (priv->cloned_mac_address, ETH_ALEN)) {
g_set_error_literal (error, g_set_error_literal (error,
NM_CONNECTION_ERROR, NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY, NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -732,6 +735,25 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return TRUE; return TRUE;
} }
static gboolean
compare_property (NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingClass *parent_class;
if (nm_streq (prop_spec->name, NM_SETTING_WIRED_CLONED_MAC_ADDRESS)) {
return nm_streq0 (NM_SETTING_WIRED_GET_PRIVATE (setting)->cloned_mac_address,
NM_SETTING_WIRED_GET_PRIVATE (other)->cloned_mac_address);
}
parent_class = NM_SETTING_CLASS (nm_setting_wired_parent_class);
return parent_class->compare_property (setting, other, prop_spec, flags);
}
/*****************************************************************************/
static void static void
clear_blacklist_item (char **item_p) clear_blacklist_item (char **item_p)
{ {
@@ -900,18 +922,19 @@ get_property (GObject *object, guint prop_id,
} }
static void static void
nm_setting_wired_class_init (NMSettingWiredClass *setting_class) nm_setting_wired_class_init (NMSettingWiredClass *setting_wired_class)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (setting_class); GObjectClass *object_class = G_OBJECT_CLASS (setting_wired_class);
NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); NMSettingClass *setting_class = NM_SETTING_CLASS (setting_wired_class);
g_type_class_add_private (setting_class, sizeof (NMSettingWiredPrivate)); g_type_class_add_private (setting_wired_class, sizeof (NMSettingWiredPrivate));
/* virtual methods */ /* virtual methods */
object_class->set_property = set_property; object_class->set_property = set_property;
object_class->get_property = get_property; object_class->get_property = get_property;
object_class->finalize = finalize; object_class->finalize = finalize;
parent_class->verify = verify; setting_class->verify = verify;
setting_class->compare_property = compare_property;
/* Properties */ /* Properties */
/** /**
@@ -1023,7 +1046,7 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
G_PARAM_READWRITE | G_PARAM_READWRITE |
NM_SETTING_PARAM_INFERRABLE | NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRED_MAC_ADDRESS, _nm_setting_class_transform_property (setting_class, NM_SETTING_WIRED_MAC_ADDRESS,
G_VARIANT_TYPE_BYTESTRING, G_VARIANT_TYPE_BYTESTRING,
_nm_utils_hwaddr_to_dbus, _nm_utils_hwaddr_to_dbus,
_nm_utils_hwaddr_from_dbus); _nm_utils_hwaddr_from_dbus);
@@ -1033,6 +1056,20 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
* *
* If specified, request that the device use this MAC address instead of its * If specified, request that the device use this MAC address instead of its
* permanent MAC address. This is known as MAC cloning or spoofing. * permanent MAC address. This is known as MAC cloning or spoofing.
*
* Beside explicitly specifing a MAC address, the special values "preserve", "permanent",
* "random" and "stable" are supported.
* "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.
*
* If unspecified, the value can be overwritten via global defaults, see manual
* of NetworkManager.conf. If still unspecified, it defaults to "permanent".
*
* On D-Bus, this field is expressed as "assigned-mac-address" or the deprecated
* "cloned-mac-address".
**/ **/
/* ---keyfile--- /* ---keyfile---
* property: cloned-mac-address * property: cloned-mac-address
@@ -1047,6 +1084,12 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
* description: Cloned (spoofed) MAC address in traditional hex-digits-and-colons * description: Cloned (spoofed) MAC address in traditional hex-digits-and-colons
* notation (e.g. 00:22:68:14:5A:99). * notation (e.g. 00:22:68:14:5A:99).
* ---end--- * ---end---
* ---dbus---
* property: cloned-mac-address
* format: byte array
* description: This D-Bus field is deprecated in favor of "assigned-mac-address"
* which is more flexible and allows specifying special variants like "random".
* ---end---
*/ */
g_object_class_install_property g_object_class_install_property
(object_class, PROP_CLONED_MAC_ADDRESS, (object_class, PROP_CLONED_MAC_ADDRESS,
@@ -1055,10 +1098,28 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
G_PARAM_READWRITE | G_PARAM_READWRITE |
NM_SETTING_PARAM_INFERRABLE | NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, _nm_setting_class_override_property (setting_class,
G_VARIANT_TYPE_BYTESTRING, NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
_nm_utils_hwaddr_to_dbus, G_VARIANT_TYPE_BYTESTRING,
_nm_utils_hwaddr_from_dbus); _nm_utils_hwaddr_cloned_get,
_nm_utils_hwaddr_cloned_set,
_nm_utils_hwaddr_cloned_not_set);
/* ---dbus---
* property: assigned-mac-address
* format: string
* description: The new field for the cloned MAC address. It can be either
* a hardware address in ASCII representation, or one of the special values
* "preserve", "permanent", "random", "random" or "stable".
* This field replaces the deprecated "cloned-mac-address" on D-Bus, which
* can only contain explict hardware addresses.
* ---end---
*/
_nm_setting_class_add_dbus_only_property (setting_class,
"assigned-mac-address",
G_VARIANT_TYPE_STRING,
_nm_utils_hwaddr_cloned_data_synth,
_nm_utils_hwaddr_cloned_data_set);
/** /**
* NMSettingWired:mac-address-blacklist: * NMSettingWired:mac-address-blacklist:
@@ -1183,7 +1244,7 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
G_PARAM_READWRITE | G_PARAM_READWRITE |
NM_SETTING_PARAM_INFERRABLE | NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRED_S390_OPTIONS, _nm_setting_class_transform_property (setting_class, NM_SETTING_WIRED_S390_OPTIONS,
G_VARIANT_TYPE ("a{ss}"), G_VARIANT_TYPE ("a{ss}"),
_nm_utils_strdict_to_dbus, _nm_utils_strdict_to_dbus,
_nm_utils_strdict_from_dbus); _nm_utils_strdict_from_dbus);

View File

@@ -22,11 +22,13 @@
#include "nm-default.h" #include "nm-default.h"
#include "nm-setting-wireless.h"
#include <string.h> #include <string.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include "nm-setting-wireless.h"
#include "nm-utils.h" #include "nm-utils.h"
#include "nm-common-macros.h"
#include "nm-utils-private.h" #include "nm-utils-private.h"
#include "nm-setting-private.h" #include "nm-setting-private.h"
@@ -801,7 +803,9 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE; return FALSE;
} }
if (priv->cloned_mac_address && !nm_utils_hwaddr_valid (priv->cloned_mac_address, ETH_ALEN)) { if ( priv->cloned_mac_address
&& !NM_CLONED_MAC_IS_SPECIAL (priv->cloned_mac_address)
&& !nm_utils_hwaddr_valid (priv->cloned_mac_address, ETH_ALEN)) {
g_set_error_literal (error, g_set_error_literal (error,
NM_CONNECTION_ERROR, NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY, NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -839,6 +843,25 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return TRUE; return TRUE;
} }
static gboolean
compare_property (NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingClass *parent_class;
if (nm_streq (prop_spec->name, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS)) {
return nm_streq0 (NM_SETTING_WIRELESS_GET_PRIVATE (setting)->cloned_mac_address,
NM_SETTING_WIRELESS_GET_PRIVATE (other)->cloned_mac_address);
}
parent_class = NM_SETTING_CLASS (nm_setting_wireless_parent_class);
return parent_class->compare_property (setting, other, prop_spec, flags);
}
/*****************************************************************************/
static GVariant * static GVariant *
nm_setting_wireless_get_security (NMSetting *setting, nm_setting_wireless_get_security (NMSetting *setting,
NMConnection *connection, NMConnection *connection,
@@ -1023,18 +1046,19 @@ get_property (GObject *object, guint prop_id,
} }
static void static void
nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class) nm_setting_wireless_class_init (NMSettingWirelessClass *setting_wireless_class)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (setting_class); GObjectClass *object_class = G_OBJECT_CLASS (setting_wireless_class);
NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); NMSettingClass *setting_class = NM_SETTING_CLASS (setting_wireless_class);
g_type_class_add_private (setting_class, sizeof (NMSettingWirelessPrivate)); g_type_class_add_private (setting_wireless_class, sizeof (NMSettingWirelessPrivate));
/* virtual methods */ /* virtual methods */
object_class->set_property = set_property; object_class->set_property = set_property;
object_class->get_property = get_property; object_class->get_property = get_property;
object_class->finalize = finalize; object_class->finalize = finalize;
parent_class->verify = verify; setting_class->verify = verify;
setting_class->compare_property = compare_property;
/* Properties */ /* Properties */
/** /**
@@ -1154,7 +1178,7 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRELESS_BSSID, _nm_setting_class_transform_property (setting_class, NM_SETTING_WIRELESS_BSSID,
G_VARIANT_TYPE_BYTESTRING, G_VARIANT_TYPE_BYTESTRING,
_nm_utils_hwaddr_to_dbus, _nm_utils_hwaddr_to_dbus,
_nm_utils_hwaddr_from_dbus); _nm_utils_hwaddr_from_dbus);
@@ -1231,7 +1255,7 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRELESS_MAC_ADDRESS, _nm_setting_class_transform_property (setting_class, NM_SETTING_WIRELESS_MAC_ADDRESS,
G_VARIANT_TYPE_BYTESTRING, G_VARIANT_TYPE_BYTESTRING,
_nm_utils_hwaddr_to_dbus, _nm_utils_hwaddr_to_dbus,
_nm_utils_hwaddr_from_dbus); _nm_utils_hwaddr_from_dbus);
@@ -1239,8 +1263,22 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
/** /**
* NMSettingWireless:cloned-mac-address: * NMSettingWireless:cloned-mac-address:
* *
* If specified, request that the Wi-Fi device use this MAC address instead * If specified, request that the device use this MAC address instead of its
* of its permanent MAC address. This is known as MAC cloning or spoofing. * permanent MAC address. This is known as MAC cloning or spoofing.
*
* Beside explicitly specifing a MAC address, the special values "preserve", "permanent",
* "random" and "stable" are supported.
* "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.
*
* If unspecified, the value can be overwritten via global defaults, see manual
* of NetworkManager.conf. If still unspecified, it defaults to "permanent".
*
* On D-Bus, this field is expressed as "assigned-mac-address" or the deprecated
* "cloned-mac-address".
**/ **/
/* ---keyfile--- /* ---keyfile---
* property: cloned-mac-address * property: cloned-mac-address
@@ -1255,6 +1293,12 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
* description: Cloned (spoofed) MAC address in traditional hex-digits-and-colons * description: Cloned (spoofed) MAC address in traditional hex-digits-and-colons
* notation (e.g. 00:22:68:14:5A:99). * notation (e.g. 00:22:68:14:5A:99).
* ---end--- * ---end---
* ---dbus---
* property: cloned-mac-address
* format: byte array
* description: This D-Bus field is deprecated in favor of "assigned-mac-address"
* which is more flexible and allows specifying special variants like "random".
* ---end---
*/ */
g_object_class_install_property g_object_class_install_property
(object_class, PROP_CLONED_MAC_ADDRESS, (object_class, PROP_CLONED_MAC_ADDRESS,
@@ -1262,10 +1306,28 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, _nm_setting_class_override_property (setting_class,
G_VARIANT_TYPE_BYTESTRING, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS,
_nm_utils_hwaddr_to_dbus, G_VARIANT_TYPE_BYTESTRING,
_nm_utils_hwaddr_from_dbus); _nm_utils_hwaddr_cloned_get,
_nm_utils_hwaddr_cloned_set,
_nm_utils_hwaddr_cloned_not_set);
/* ---dbus---
* property: assigned-mac-address
* format: string
* description: The new field for the cloned MAC address. It can be either
* a hardware address in ASCII representation, or one of the special values
* "preserve", "permanent", "random", "random" or "stable".
* This field replaces the deprecated "cloned-mac-address" on D-Bus, which
* can only contain explict hardware addresses.
* ---end---
*/
_nm_setting_class_add_dbus_only_property (setting_class,
"assigned-mac-address",
G_VARIANT_TYPE_STRING,
_nm_utils_hwaddr_cloned_data_synth,
_nm_utils_hwaddr_cloned_data_set);
/** /**
* NMSettingWireless:mac-address-blacklist: * NMSettingWireless:mac-address-blacklist:
@@ -1428,7 +1490,7 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
* NetworkManager daemons. * NetworkManager daemons.
* ---end--- * ---end---
*/ */
_nm_setting_class_add_dbus_only_property (parent_class, "security", _nm_setting_class_add_dbus_only_property (setting_class, "security",
G_VARIANT_TYPE_STRING, G_VARIANT_TYPE_STRING,
nm_setting_wireless_get_security, NULL); nm_setting_wireless_get_security, NULL);
} }

View File

@@ -36,6 +36,29 @@ gboolean _nm_utils_team_config_equal (const char *conf1, const char *conf2, g
/* D-Bus transform funcs */ /* D-Bus transform funcs */
GVariant *_nm_utils_hwaddr_cloned_get (NMSetting *setting,
const char *property);
gboolean _nm_utils_hwaddr_cloned_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value,
NMSettingParseFlags parse_flags,
GError **error);
gboolean _nm_utils_hwaddr_cloned_not_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
NMSettingParseFlags parse_flags,
GError **error);
GVariant * _nm_utils_hwaddr_cloned_data_synth (NMSetting *setting,
NMConnection *connection,
const char *property);
gboolean _nm_utils_hwaddr_cloned_data_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value,
NMSettingParseFlags parse_flags,
GError **error);
GVariant * _nm_utils_hwaddr_to_dbus (const GValue *prop_value); GVariant * _nm_utils_hwaddr_to_dbus (const GValue *prop_value);
void _nm_utils_hwaddr_from_dbus (GVariant *dbus_value, void _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
GValue *prop_value); GValue *prop_value);

View File

@@ -37,6 +37,7 @@
#include <jansson.h> #include <jansson.h>
#endif #endif
#include "nm-common-macros.h"
#include "nm-utils-private.h" #include "nm-utils-private.h"
#include "nm-setting-private.h" #include "nm-setting-private.h"
#include "crypto.h" #include "crypto.h"
@@ -3313,14 +3314,14 @@ nm_utils_hwaddr_matches (gconstpointer hwaddr1,
return !memcmp (hwaddr1, hwaddr2, hwaddr1_len); return !memcmp (hwaddr1, hwaddr2, hwaddr1_len);
} }
GVariant * /*****************************************************************************/
_nm_utils_hwaddr_to_dbus (const GValue *prop_value)
static GVariant *
_nm_utils_hwaddr_to_dbus_impl (const char *str)
{ {
const char *str;
guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
int len; int len;
str = g_value_get_string (prop_value);
if (!str) if (!str)
return NULL; return NULL;
@@ -3334,6 +3335,103 @@ _nm_utils_hwaddr_to_dbus (const GValue *prop_value)
return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, buf, len, 1); return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, buf, len, 1);
} }
GVariant *
_nm_utils_hwaddr_cloned_get (NMSetting *setting,
const char *property)
{
gs_free char *addr = NULL;
nm_assert (nm_streq0 (property, "cloned-mac-address"));
g_object_get (setting, "cloned-mac-address", &addr, NULL);
return _nm_utils_hwaddr_to_dbus_impl (addr);
}
gboolean
_nm_utils_hwaddr_cloned_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value,
NMSettingParseFlags parse_flags,
GError **error)
{
gsize length;
const guint8 *array;
char *str;
nm_assert (nm_streq0 (property, "cloned-mac-address"));
if (!_nm_setting_use_legacy_property (setting, connection_dict, "cloned-mac-address", "assigned-mac-address"))
return TRUE;
length = 0;
array = g_variant_get_fixed_array (value, &length, 1);
if (!length)
return TRUE;
str = nm_utils_hwaddr_ntoa (array, length);
g_object_set (setting,
"cloned-mac-address",
str,
NULL);
g_free (str);
return TRUE;
}
gboolean
_nm_utils_hwaddr_cloned_not_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
NMSettingParseFlags parse_flags,
GError **error)
{
nm_assert (nm_streq0 (property, "cloned-mac-address"));
return TRUE;
}
GVariant *
_nm_utils_hwaddr_cloned_data_synth (NMSetting *setting,
NMConnection *connection,
const char *property)
{
gs_free char *addr = NULL;
nm_assert (nm_streq0 (property, "assigned-mac-address"));
g_object_get (setting,
"cloned-mac-address",
&addr,
NULL);
return addr ? g_variant_new_string (addr) : NULL;
}
gboolean
_nm_utils_hwaddr_cloned_data_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value,
NMSettingParseFlags parse_flags,
GError **error)
{
nm_assert (nm_streq0 (property, "assigned-mac-address"));
if (_nm_setting_use_legacy_property (setting, connection_dict, "cloned-mac-address", "assigned-mac-address"))
return TRUE;
g_object_set (setting,
"cloned-mac-address",
g_variant_get_string (value, NULL),
NULL);
return TRUE;
}
GVariant *
_nm_utils_hwaddr_to_dbus (const GValue *prop_value)
{
return _nm_utils_hwaddr_to_dbus_impl (g_value_get_string (prop_value));
}
void void
_nm_utils_hwaddr_from_dbus (GVariant *dbus_value, _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
GValue *prop_value) GValue *prop_value)
@@ -3346,6 +3444,8 @@ _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
g_value_take_string (prop_value, str); g_value_take_string (prop_value, str);
} }
/*****************************************************************************/
/** /**
* nm_utils_bin2hexstr: * nm_utils_bin2hexstr:
* @src: (type guint8) (array length=len): an array of bytes * @src: (type guint8) (array length=len): an array of bytes

View File

@@ -2449,6 +2449,90 @@ test_setting_compare_routes (void)
g_clear_pointer (&result, g_hash_table_unref); g_clear_pointer (&result, g_hash_table_unref);
} }
static void
test_setting_compare_wired_cloned_mac_address (void)
{
gs_unref_object NMSetting *old = NULL, *new = NULL;
gboolean success;
gs_free char *str1 = NULL;
old = nm_setting_wired_new ();
g_object_set (old,
NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "stable",
NULL);
g_assert_cmpstr ("stable", ==, nm_setting_wired_get_cloned_mac_address ((NMSettingWired *) old));
g_object_get (old, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("stable", ==, str1);
g_clear_pointer (&str1, g_free);
new = nm_setting_duplicate (old);
g_object_set (new, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "11:22:33:44:55:66", NULL);
g_assert_cmpstr ("11:22:33:44:55:66", ==, nm_setting_wired_get_cloned_mac_address ((NMSettingWired *) new));
g_object_get (new, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("11:22:33:44:55:66", ==, str1);
g_clear_pointer (&str1, g_free);
success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
g_assert (!success);
g_clear_object (&new);
new = nm_setting_duplicate (old);
g_object_set (new, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "stable-bia", NULL);
g_assert_cmpstr ("stable-bia", ==, nm_setting_wired_get_cloned_mac_address ((NMSettingWired *) new));
g_object_get (new, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("stable-bia", ==, str1);
g_clear_pointer (&str1, g_free);
success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
g_assert (!success);
g_clear_object (&new);
}
static void
test_setting_compare_wireless_cloned_mac_address (void)
{
gs_unref_object NMSetting *old = NULL, *new = NULL;
gboolean success;
gs_free char *str1 = NULL;
old = nm_setting_wireless_new ();
g_object_set (old,
NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, "stable",
NULL);
g_assert_cmpstr ("stable", ==, nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) old));
g_object_get (old, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("stable", ==, str1);
g_clear_pointer (&str1, g_free);
new = nm_setting_duplicate (old);
g_object_set (new, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, "11:22:33:44:55:66", NULL);
g_assert_cmpstr ("11:22:33:44:55:66", ==, nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) new));
g_object_get (new, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("11:22:33:44:55:66", ==, str1);
g_clear_pointer (&str1, g_free);
success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
g_assert (!success);
g_clear_object (&new);
new = nm_setting_duplicate (old);
g_object_set (new, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, "stable-bia", NULL);
g_assert_cmpstr ("stable-bia", ==, nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) new));
g_object_get (new, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("stable-bia", ==, str1);
g_clear_pointer (&str1, g_free);
success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
g_assert (!success);
g_clear_object (&new);
}
static void static void
test_setting_compare_timestamp (void) test_setting_compare_timestamp (void)
{ {
@@ -5202,6 +5286,8 @@ int main (int argc, char **argv)
g_test_add_func ("/core/general/test_setting_compare_id", test_setting_compare_id); g_test_add_func ("/core/general/test_setting_compare_id", test_setting_compare_id);
g_test_add_func ("/core/general/test_setting_compare_addresses", test_setting_compare_addresses); g_test_add_func ("/core/general/test_setting_compare_addresses", test_setting_compare_addresses);
g_test_add_func ("/core/general/test_setting_compare_routes", test_setting_compare_routes); g_test_add_func ("/core/general/test_setting_compare_routes", test_setting_compare_routes);
g_test_add_func ("/core/general/test_setting_compare_wired_cloned_mac_address", test_setting_compare_wired_cloned_mac_address);
g_test_add_func ("/core/general/test_setting_compare_wirless_cloned_mac_address", test_setting_compare_wireless_cloned_mac_address);
g_test_add_func ("/core/general/test_setting_compare_timestamp", test_setting_compare_timestamp); g_test_add_func ("/core/general/test_setting_compare_timestamp", test_setting_compare_timestamp);
#define ADD_FUNC(name, func, secret_flags, comp_flags, remove_secret) \ #define ADD_FUNC(name, func, secret_flags, comp_flags, remove_secret) \
g_test_add_data_func_full ("/core/general/" G_STRINGIFY (func) "_" name, \ g_test_add_data_func_full ("/core/general/" G_STRINGIFY (func) "_" name, \

View File

@@ -565,6 +565,10 @@ ipv6.ip6-privacy=0
<varlistentry> <varlistentry>
<term><varname>connection.lldp</varname></term> <term><varname>connection.lldp</varname></term>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>ethernet.cloned-mac-address</varname></term>
<listitem><para>If left unspecified, it defaults to "permanent".</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>ethernet.wake-on-lan</varname></term> <term><varname>ethernet.wake-on-lan</varname></term>
</varlistentry> </varlistentry>
@@ -592,6 +596,10 @@ ipv6.ip6-privacy=0
<term><varname>vpn.timeout</varname></term> <term><varname>vpn.timeout</varname></term>
<listitem><para>If left unspecified, default value of 60 seconds is used.</para></listitem> <listitem><para>If left unspecified, default value of 60 seconds is used.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>wifi.cloned-mac-address</varname></term>
<listitem><para>If left unspecified, it defaults to "permanent".</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>wifi.mac-address-randomization</varname></term> <term><varname>wifi.mac-address-randomization</varname></term>
<listitem><para>If left unspecified, MAC address randomization is disabled.</para></listitem> <listitem><para>If left unspecified, MAC address randomization is disabled.</para></listitem>

View File

@@ -38,6 +38,21 @@
#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS "org.freedesktop.NetworkManager.settings.modify.global-dns" #define NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS "org.freedesktop.NetworkManager.settings.modify.global-dns"
#define NM_AUTH_PERMISSION_RELOAD "org.freedesktop.NetworkManager.reload" #define NM_AUTH_PERMISSION_RELOAD "org.freedesktop.NetworkManager.reload"
#define NM_CLONED_MAC_PRESERVE "preserve"
#define NM_CLONED_MAC_PERMANENT "permanent"
#define NM_CLONED_MAC_RANDOM "random"
#define NM_CLONED_MAC_STABLE "stable"
static inline gboolean
NM_CLONED_MAC_IS_SPECIAL (const char *str)
{
return NM_IN_STRSET (str,
NM_CLONED_MAC_PRESERVE,
NM_CLONED_MAC_PERMANENT,
NM_CLONED_MAC_RANDOM,
NM_CLONED_MAC_STABLE);
}
/******************************************************************************/ /******************************************************************************/
#endif /* __NM_COMMON_MACROS_H__ */ #endif /* __NM_COMMON_MACROS_H__ */

View File

@@ -529,8 +529,8 @@ check_connection_mac_address (NMConnection *orig,
static gboolean static gboolean
check_connection_cloned_mac_address (NMConnection *orig, check_connection_cloned_mac_address (NMConnection *orig,
NMConnection *candidate, NMConnection *candidate,
GHashTable *settings) GHashTable *settings)
{ {
GHashTable *props; GHashTable *props;
const char *orig_mac = NULL, *cand_mac = NULL; const char *orig_mac = NULL, *cand_mac = NULL;
@@ -551,6 +551,12 @@ check_connection_cloned_mac_address (NMConnection *orig,
if (s_wired_cand) if (s_wired_cand)
cand_mac = nm_setting_wired_get_cloned_mac_address (s_wired_cand); cand_mac = nm_setting_wired_get_cloned_mac_address (s_wired_cand);
/* special cloned mac address entires are accepted. */
if (NM_CLONED_MAC_IS_SPECIAL (orig_mac))
orig_mac = NULL;
if (NM_CLONED_MAC_IS_SPECIAL (cand_mac))
cand_mac = NULL;
if (!orig_mac || !cand_mac) { if (!orig_mac || !cand_mac) {
remove_from_hash (settings, props, remove_from_hash (settings, props,
NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_SETTING_NAME,

View File

@@ -804,18 +804,13 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{ {
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
NMSettingWired *s_wired;
const char *cloned_mac = NULL;
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage1_prepare (dev, reason); ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage1_prepare (dev, reason);
if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
s_wired = (NMSettingWired *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_WIRED); nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE);
if (s_wired)
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
nm_device_hw_addr_set (dev, cloned_mac);
/* If we're re-activating a PPPoE connection a short while after /* If we're re-activating a PPPoE connection a short while after
* a previous PPPoE connection was torn down, wait a bit to allow the * a previous PPPoE connection was torn down, wait a bit to allow the

View File

@@ -502,8 +502,6 @@ update_connection (NMDevice *device, NMConnection *connection)
static NMActStageReturn static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{ {
NMSettingWired *s_wired;
const char *cloned_mac = NULL;
NMActStageReturn ret; NMActStageReturn ret;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@@ -512,11 +510,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
if (ret != NM_ACT_STAGE_RETURN_SUCCESS) if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret; return ret;
s_wired = (NMSettingWired *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_WIRED); nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE);
if (s_wired)
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
nm_device_hw_addr_set (dev, cloned_mac);
return TRUE; return TRUE;
} }

View File

@@ -57,6 +57,7 @@ gboolean nm_device_bring_up (NMDevice *self, gboolean wait, gboolean *no_firmwar
void nm_device_take_down (NMDevice *self, gboolean block); void nm_device_take_down (NMDevice *self, gboolean block);
gboolean nm_device_hw_addr_set (NMDevice *device, const char *addr); gboolean nm_device_hw_addr_set (NMDevice *device, const char *addr);
gboolean nm_device_hw_addr_set_cloned (NMDevice *device, NMConnection *connection, gboolean is_wifi);
gboolean nm_device_hw_addr_reset (NMDevice *device); gboolean nm_device_hw_addr_reset (NMDevice *device);
void nm_device_set_firmware_missing (NMDevice *self, gboolean missing); void nm_device_set_firmware_missing (NMDevice *self, gboolean missing);
@@ -107,6 +108,8 @@ void nm_device_queue_recheck_available (NMDevice *device,
void nm_device_set_wwan_ip4_config (NMDevice *device, NMIP4Config *config); void nm_device_set_wwan_ip4_config (NMDevice *device, NMIP4Config *config);
void nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config); void nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config);
gboolean nm_device_hw_addr_is_explict (NMDevice *device);
void nm_device_ip_method_failed (NMDevice *self, int family, NMDeviceStateReason reason); void nm_device_ip_method_failed (NMDevice *self, int family, NMDeviceStateReason reason);
gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value); gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value);

View File

@@ -291,8 +291,6 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
{ {
NMDeviceTun *self = NM_DEVICE_TUN (device); NMDeviceTun *self = NM_DEVICE_TUN (device);
NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
NMSettingWired *s_wired;
const char *cloned_mac = NULL;
NMActStageReturn ret; NMActStageReturn ret;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@@ -305,10 +303,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
if (g_strcmp0 (priv->mode, "tap")) if (g_strcmp0 (priv->mode, "tap"))
return NM_ACT_STAGE_RETURN_SUCCESS; return NM_ACT_STAGE_RETURN_SUCCESS;
s_wired = (NMSettingWired *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRED); nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE);
if (s_wired)
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
nm_device_hw_addr_set (device, cloned_mac);
return NM_ACT_STAGE_RETURN_SUCCESS; return NM_ACT_STAGE_RETURN_SUCCESS;
} }

View File

@@ -87,7 +87,6 @@ parent_hwaddr_maybe_changed (NMDevice *parent,
{ {
NMDeviceVlan *self = NM_DEVICE_VLAN (user_data); NMDeviceVlan *self = NM_DEVICE_VLAN (user_data);
NMConnection *connection; NMConnection *connection;
NMSettingWired *s_wired;
const char *new_mac, *old_mac; const char *new_mac, *old_mac;
NMSettingIPConfig *s_ip6; NMSettingIPConfig *s_ip6;
@@ -100,11 +99,8 @@ parent_hwaddr_maybe_changed (NMDevice *parent,
return; return;
/* Update the VLAN MAC only if configuration does not specify one */ /* Update the VLAN MAC only if configuration does not specify one */
s_wired = nm_connection_get_setting_wired (connection); if (nm_device_hw_addr_is_explict (self))
if (s_wired) { return;
if (nm_setting_wired_get_cloned_mac_address (s_wired))
return;
}
old_mac = nm_device_get_hw_address (self); old_mac = nm_device_get_hw_address (self);
new_mac = nm_device_get_hw_address (parent); new_mac = nm_device_get_hw_address (parent);
@@ -554,8 +550,6 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{ {
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (dev); NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (dev);
NMSettingVlan *s_vlan; NMSettingVlan *s_vlan;
NMSettingWired *s_wired;
const char *cloned_mac = NULL;
NMActStageReturn ret; NMActStageReturn ret;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@@ -564,10 +558,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
if (ret != NM_ACT_STAGE_RETURN_SUCCESS) if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret; return ret;
s_wired = (NMSettingWired *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_WIRED); nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE);
if (s_wired)
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
nm_device_hw_addr_set (dev, cloned_mac);
/* Change MAC address to parent's one if needed */ /* Change MAC address to parent's one if needed */
if (priv->parent) if (priv->parent)

View File

@@ -511,8 +511,6 @@ update_connection (NMDevice *device, NMConnection *connection)
static NMActStageReturn static NMActStageReturn
act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
{ {
NMSettingWired *s_wired;
const char *cloned_mac = NULL;
NMActStageReturn ret; NMActStageReturn ret;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@@ -521,10 +519,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
if (ret != NM_ACT_STAGE_RETURN_SUCCESS) if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret; return ret;
s_wired = (NMSettingWired *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRED); nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE);
if (s_wired)
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
nm_device_hw_addr_set (device, cloned_mac);
return NM_ACT_STAGE_RETURN_SUCCESS; return NM_ACT_STAGE_RETURN_SUCCESS;
} }

View File

@@ -209,6 +209,13 @@ typedef struct {
NMIP4Config **configs; NMIP4Config **configs;
} ArpingData; } ArpingData;
typedef enum {
HW_ADDR_TYPE_UNSET = 0,
HW_ADDR_TYPE_PERMANENT,
HW_ADDR_TYPE_EXPLICIT,
HW_ADDR_TYPE_GENERATED,
} HwAddrType;
typedef struct _NMDevicePrivate { typedef struct _NMDevicePrivate {
bool in_state_changed; bool in_state_changed;
@@ -226,7 +233,12 @@ typedef struct _NMDevicePrivate {
char * udi; char * udi;
char * iface; /* may change, could be renamed by user */ char * iface; /* may change, could be renamed by user */
int ifindex; int ifindex;
guint hw_addr_len;
guint8 /*HwAddrType*/ hw_addr_type;
bool real; bool real;
char * ip_iface; char * ip_iface;
int ip_ifindex; int ip_ifindex;
NMDeviceType type; NMDeviceType type;
@@ -243,7 +255,6 @@ typedef struct _NMDevicePrivate {
bool hw_addr_perm_fake:1; /* whether the permanent HW address could not be read and is a fake */ bool hw_addr_perm_fake:1; /* whether the permanent HW address could not be read and is a fake */
GHashTable * available_connections; GHashTable * available_connections;
char * hw_addr; char * hw_addr;
guint hw_addr_len;
char * hw_addr_perm; char * hw_addr_perm;
char * hw_addr_initial; char * hw_addr_initial;
char * physical_port_id; char * physical_port_id;
@@ -2357,6 +2368,7 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
_notify (self, PROP_PHYSICAL_PORT_ID); _notify (self, PROP_PHYSICAL_PORT_ID);
} }
priv->hw_addr_type = HW_ADDR_TYPE_UNSET;
g_clear_pointer (&priv->hw_addr_perm, g_free); g_clear_pointer (&priv->hw_addr_perm, g_free);
_notify (self, PROP_PERM_HW_ADDRESS); _notify (self, PROP_PERM_HW_ADDRESS);
g_clear_pointer (&priv->hw_addr_initial, g_free); g_clear_pointer (&priv->hw_addr_initial, g_free);
@@ -11421,6 +11433,8 @@ nm_device_update_initial_hw_address (NMDevice *self)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
priv->hw_addr_type = HW_ADDR_TYPE_UNSET;
if ( priv->hw_addr if ( priv->hw_addr
&& !nm_streq0 (priv->hw_addr_initial, priv->hw_addr)) { && !nm_streq0 (priv->hw_addr_initial, priv->hw_addr)) {
g_free (priv->hw_addr_initial); g_free (priv->hw_addr_initial);
@@ -11479,6 +11493,50 @@ nm_device_update_permanent_hw_address (NMDevice *self)
_notify (self, PROP_PERM_HW_ADDRESS); _notify (self, PROP_PERM_HW_ADDRESS);
} }
static const char *
_get_cloned_mac_address_setting (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_addr)
{
NMSetting *setting;
const char *addr = NULL;
nm_assert (out_addr && !*out_addr);
setting = nm_connection_get_setting (connection,
is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED);
if (setting) {
addr = is_wifi
? nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) setting)
: nm_setting_wired_get_cloned_mac_address ((NMSettingWired *) setting);
}
if (!addr) {
gs_free char *a = NULL;
a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
is_wifi ? "wifi.cloned-mac-address" : "ethernet.cloned-mac-address",
self);
if ( !a
|| ( !NM_CLONED_MAC_IS_SPECIAL (a)
&& !nm_utils_hwaddr_valid (a, ETH_ALEN)))
addr = NM_CLONED_MAC_PERMANENT;
else
addr = *out_addr = g_steal_pointer (&a);
}
return addr;
}
gboolean
nm_device_hw_addr_is_explict (NMDevice *self)
{
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
return !NM_IN_SET (priv->hw_addr_type, HW_ADDR_TYPE_PERMANENT, HW_ADDR_TYPE_UNSET);
}
static gboolean static gboolean
_hw_addr_set (NMDevice *self, _hw_addr_set (NMDevice *self,
const char *addr, const char *addr,
@@ -11508,10 +11566,8 @@ _hw_addr_set (NMDevice *self,
if (!hw_addr_len) if (!hw_addr_len)
hw_addr_len = _nm_utils_hwaddr_length (addr); hw_addr_len = _nm_utils_hwaddr_length (addr);
if ( !hw_addr_len if ( !hw_addr_len
|| !nm_utils_hwaddr_aton (addr, addr_bytes, hw_addr_len)) { || !nm_utils_hwaddr_aton (addr, addr_bytes, hw_addr_len))
_LOGW (LOGD_DEVICE, "set-hw-addr: invalid MAC address %s", addr); g_return_val_if_reached (FALSE);
return FALSE;
}
_LOGT (LOGD_DEVICE, "set-hw-addr: setting MAC address to '%s'...", addr); _LOGT (LOGD_DEVICE, "set-hw-addr: setting MAC address to '%s'...", addr);
@@ -11535,7 +11591,9 @@ _hw_addr_set (NMDevice *self,
_LOGW (LOGD_DEVICE, "set-hw-addr: failed to %s MAC address to %s", _LOGW (LOGD_DEVICE, "set-hw-addr: failed to %s MAC address to %s",
detail, addr); detail, addr);
} }
nm_device_bring_up (self, TRUE, NULL);
if (!nm_device_bring_up (self, TRUE, NULL))
return FALSE;
return success; return success;
} }
@@ -11549,12 +11607,73 @@ nm_device_hw_addr_set (NMDevice *self, const char *addr)
priv = NM_DEVICE_GET_PRIVATE (self); priv = NM_DEVICE_GET_PRIVATE (self);
if (!addr) { if (!addr)
g_return_val_if_reached (FALSE);
/* this is called by NMDeviceVlan to take the MAC address from the parent.
* In this case, it's like setting it to PERMANENT. */
priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT;
return _hw_addr_set (self, addr, "set");
}
gboolean
nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi)
{
NMDevicePrivate *priv;
gs_free char *hw_addr_tmp = NULL;
gs_free char *hw_addr_generated = NULL;
const char *addr;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
if (!connection)
g_return_val_if_reached (FALSE);
addr = _get_cloned_mac_address_setting (self, connection, is_wifi, &hw_addr_tmp);
if (nm_streq (addr, NM_CLONED_MAC_PRESERVE))
return TRUE;
if (nm_streq (addr, NM_CLONED_MAC_PERMANENT)) {
addr = nm_device_get_permanent_hw_address (self, TRUE); addr = nm_device_get_permanent_hw_address (self, TRUE);
if (!addr) if (!addr)
return FALSE; return FALSE;
priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT;
} else if (NM_IN_STRSET (addr, NM_CLONED_MAC_RANDOM)) {
hw_addr_generated = nm_utils_hw_addr_gen_random_eth ();
if (!hw_addr_generated) {
_LOGW (LOGD_DEVICE, "set-hw-addr: failed to generate %s MAC address", "random");
return FALSE;
}
priv->hw_addr_type = HW_ADDR_TYPE_GENERATED;
addr = hw_addr_generated;
} else if (NM_IN_STRSET (addr, NM_CLONED_MAC_STABLE)) {
NMUtilsStableType stable_type;
const char *stable_id;
stable_id = _get_stable_id (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));
}
if (!hw_addr_generated) {
_LOGW (LOGD_DEVICE, "set-hw-addr: failed to generate %s MAC address", "stable");
return FALSE;
}
priv->hw_addr_type = HW_ADDR_TYPE_GENERATED;
addr = hw_addr_generated;
} else {
/* this must be a valid address. Otherwise, we shouldn't come here. */
if (_nm_utils_hwaddr_length (addr) <= 0) {
g_return_val_if_reached (FALSE);
}
priv->hw_addr_type = HW_ADDR_TYPE_EXPLICIT;
} }
return _hw_addr_set (self, addr, "set");
return _hw_addr_set (self, addr, "set-cloned");
} }
gboolean gboolean
@@ -11567,9 +11686,17 @@ nm_device_hw_addr_reset (NMDevice *self)
priv = NM_DEVICE_GET_PRIVATE (self); priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->hw_addr_type == HW_ADDR_TYPE_UNSET)
return TRUE;
priv->hw_addr_type = HW_ADDR_TYPE_UNSET;
addr = nm_device_get_initial_hw_address (self); addr = nm_device_get_initial_hw_address (self);
if (!addr) if (!addr) {
return FALSE; /* as hw_addr_type is not UNSET, we expect that we can get an
* initial address to which to reset. */
g_return_val_if_reached (FALSE);
}
return _hw_addr_set (self, addr, "reset"); return _hw_addr_set (self, addr, "reset");
} }

View File

@@ -2275,7 +2275,6 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
NMActRequest *req; NMActRequest *req;
NMConnection *connection; NMConnection *connection;
NMSettingWireless *s_wireless; NMSettingWireless *s_wireless;
const char *cloned_mac;
const char *mode; const char *mode;
const char *ap_path; const char *ap_path;
@@ -2316,8 +2315,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
} }
/* Set spoof MAC to the interface */ /* Set spoof MAC to the interface */
cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless); nm_device_hw_addr_set_cloned (device, connection, TRUE);
nm_device_hw_addr_set (device, cloned_mac);
/* AP mode never uses a specific object or existing scanned AP */ /* AP mode never uses a specific object or existing scanned AP */
if (priv->mode != NM_802_11_MODE_AP) { if (priv->mode != NM_802_11_MODE_AP) {

View File

@@ -3173,6 +3173,100 @@ nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType stable_type,
secret_key, key_len, error); secret_key, key_len, error);
} }
/*****************************************************************************/
static void
_hw_addr_eth_complete (guint8 *bin_addr)
{
/* this LSB of the first octet cannot be set,
* it means Unicast vs. Multicast */
bin_addr[0] &= ~1;
/* the second LSB of the first octet means
* "globally unique, OUI enforced, BIA (burned-in-address)"
* vs. "locally-administered" */
bin_addr[0] |= 2;
}
char *
nm_utils_hw_addr_gen_random_eth (void)
{
guint8 bin_addr[ETH_ALEN];
if (nm_utils_read_urandom (bin_addr, ETH_ALEN) < 0)
return NULL;
_hw_addr_eth_complete (bin_addr);
return nm_utils_hwaddr_ntoa (bin_addr, ETH_ALEN);
}
static char *
_hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
const char *stable_id,
const guint8 *secret_key,
gsize key_len,
const char *ifname)
{
GChecksum *sum;
guint32 tmp;
guint8 digest[32];
gsize len = sizeof (digest);
guint8 bin_addr[ETH_ALEN];
guint8 stable_type_uint8;
nm_assert (stable_id);
nm_assert (NM_IN_SET (stable_type,
NM_UTILS_STABLE_TYPE_UUID,
NM_UTILS_STABLE_TYPE_STABLE_ID));
nm_assert (secret_key);
sum = g_checksum_new (G_CHECKSUM_SHA256);
if (!sum)
return NULL;
key_len = MIN (key_len, G_MAXUINT32);
stable_type_uint8 = stable_type;
g_checksum_update (sum, (const guchar *) &stable_type_uint8, sizeof (stable_type_uint8));
tmp = htonl ((guint32) key_len);
g_checksum_update (sum, (const guchar *) &tmp, sizeof (tmp));
g_checksum_update (sum, (const guchar *) secret_key, key_len);
g_checksum_update (sum, (const guchar *) (ifname ?: ""), ifname ? (strlen (ifname) + 1) : 1);
g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id) + 1);
g_checksum_get_digest (sum, digest, &len);
g_checksum_free (sum);
g_return_val_if_fail (len == 32, NULL);
memcpy (bin_addr, digest, ETH_ALEN);
_hw_addr_eth_complete (bin_addr);
return nm_utils_hwaddr_ntoa (bin_addr, ETH_ALEN);
}
char *
nm_utils_hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
const char *stable_id,
const char *ifname)
{
gs_free guint8 *secret_key = NULL;
gsize key_len = 0;
g_return_val_if_fail (stable_id, NULL);
secret_key = nm_utils_secret_key_read (&key_len, NULL);
if (!secret_key)
return NULL;
return _hw_addr_gen_stable_eth (stable_type,
stable_id,
secret_key,
key_len,
ifname);
}
/*****************************************************************************/
/** /**
* nm_utils_setpgid: * nm_utils_setpgid:
* @unused: unused * @unused: unused

View File

@@ -371,6 +371,11 @@ gboolean nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType id_type,
guint dad_counter, guint dad_counter,
GError **error); GError **error);
char *nm_utils_hw_addr_gen_random_eth (void);
char *nm_utils_hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
const char *stable_id,
const char *iname);
void nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len); void nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len);
void nm_utils_setpgid (gpointer unused); void nm_utils_setpgid (gpointer unused);

View File

@@ -54,10 +54,45 @@ test_stable_privacy (void)
inet_pton (AF_INET6, "1234::", &addr1); inet_pton (AF_INET6, "1234::", &addr1);
_set_stable_privacy (NM_UTILS_STABLE_TYPE_STABLE_ID, &addr1, "eth666", "stable-id-1", 0, (guint8 *) "key", 3, NULL); _set_stable_privacy (NM_UTILS_STABLE_TYPE_STABLE_ID, &addr1, "eth666", "stable-id-1", 0, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "1234::4944:67b0:7a6c:1cf"); nmtst_assert_ip6_address (&addr1, "1234::4944:67b0:7a6c:1cf");
} }
/*******************************************/ /*****************************************************************************/
static void
_do_test_hw_addr (NMUtilsStableType stable_type,
const char *stable_id,
const guint8 *secret_key,
gsize key_len,
const char *ifname,
const char *expected)
{
gs_free char *generated = NULL;
g_assert (expected);
g_assert (nm_utils_hwaddr_valid (expected, ETH_ALEN));
generated = _hw_addr_gen_stable_eth (stable_type,
stable_id,
secret_key,
key_len,
ifname);
g_assert (generated);
g_assert (nm_utils_hwaddr_valid (generated, ETH_ALEN));
g_assert_cmpstr (generated, ==, expected);
g_assert (nm_utils_hwaddr_matches (generated, -1, expected, -1));
}
#define do_test_hw_addr(stable_type, stable_id, secret_key, ifname, expected) \
_do_test_hw_addr ((stable_type), (stable_id), (const guint8 *) ""secret_key"", NM_STRLEN (secret_key), (ifname), ""expected"")
static void
test_hw_addr_gen_stable_eth (void)
{
do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "06:0D:CD:0C:9E:2C");
do_test_hw_addr (NM_UTILS_STABLE_TYPE_STABLE_ID, "stable-1", "key1", "eth0", "C6:AE:A9:9A:76:09");
}
/*****************************************************************************/
NMTST_DEFINE (); NMTST_DEFINE ();
@@ -67,6 +102,7 @@ main (int argc, char **argv)
nmtst_init_with_logging (&argc, &argv, NULL, "ALL"); nmtst_init_with_logging (&argc, &argv, NULL, "ALL");
g_test_add_func ("/utils/stable_privacy", test_stable_privacy); g_test_add_func ("/utils/stable_privacy", test_stable_privacy);
g_test_add_func ("/utils/hw_addr_gen_stable_eth", test_hw_addr_gen_stable_eth);
return g_test_run (); return g_test_run ();
} }