mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-06-10 23:08:28 +02:00
libnm-core: add ipv6.dhcp-duid property
allow to specify the DUID to be used int the DHCPv6 client identifier
option: the dhcp-duid property accepts either a hex string or the
special values "lease", "llt", "ll", "stable-llt", "stable-ll" and
"stable-uuid".
"lease": give priority to the DUID available in the lease file if any,
otherwise fallback to a global default dependant on the dhcp
client used. This is the default and reflects how the DUID
was managed previously.
"ll": enforce generation and use of LL type DUID based on the current
hardware address.
"llt": enforce generation and use of LLT type DUID based on the current
hardware address and a stable time field.
"stable-ll": enforce generation and use of LL type DUID based on a
link layer address derived from the stable id.
"stable-llt": enforce generation and use of LLT type DUID based on
a link layer address and a timestamp both derived from the
stable id.
"stable-uuid": enforce generation and use of a UUID type DUID based on a
uuid generated from the stable id.
This commit is contained in:
parent
fcc6bf7198
commit
7a0b6b17bb
16 changed files with 381 additions and 12 deletions
|
|
@ -152,7 +152,7 @@
|
|||
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.")
|
||||
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently only VPN connections are supported.")
|
||||
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SLAVE_TYPE N_("Setting name of the device type of this slave's master connection (eg, \"bond\"), or NULL if this connection is not a slave.")
|
||||
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${DEVICE}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds the the interface name of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.")
|
||||
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${DEVICE}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds the the interface name of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.")
|
||||
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).")
|
||||
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).")
|
||||
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").")
|
||||
|
|
@ -233,6 +233,7 @@
|
|||
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. On D-Bus, the absence of an addr-gen-mode setting equals enabling stable-privacy. For keyfile plugin, the absence of the setting on disk means EUI64 so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.")
|
||||
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES N_("Array of IP addresses.")
|
||||
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.")
|
||||
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_DUID N_("A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value \"lease\" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and \"dhclient\" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values \"llt\" and \"ll\" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values \"stable-llt\", \"stable-ll\" and \"stable-uuid\" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. So, the link-layer address of \"stable-ll\" and \"stable-llt\" will be a generated address derived from the stable id. The DUID-LLT time value in the \"stable-llt\" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in \"llt\"). When the property is unset, the global value provided for \"ipv6.dhcp-duid\" is used. If no global value is provided, the default \"lease\" value is assumed.")
|
||||
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.")
|
||||
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
|
||||
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.")
|
||||
|
|
|
|||
|
|
@ -508,4 +508,7 @@ _nm_connection_type_is_master (const char *type)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean _nm_utils_dhcp_duid_valid (const char *duid, GBytes **out_duid_bin);
|
||||
|
||||
/*****************************************************************************/
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1544,7 +1544,8 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
|
|||
* with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the
|
||||
* generated cloned MAC address for ethernet.cloned-mac-address=stable
|
||||
* and wifi.cloned-mac-address=stable. It is also used as DHCP client
|
||||
* identifier with ipv4.dhcp-client-id=stable.
|
||||
* identifier with ipv4.dhcp-client-id=stable and to derive the DHCP
|
||||
* DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid].
|
||||
*
|
||||
* Note that depending on the context where it is used, other parameters are
|
||||
* also seeded into the generation algorithm. For example, a per-host key
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "nm-setting-private.h"
|
||||
#include "nm-core-enum-types.h"
|
||||
#include "nm-core-internal.h"
|
||||
|
||||
/**
|
||||
* SECTION:nm-setting-ip6-config
|
||||
|
|
@ -61,6 +62,7 @@ typedef struct {
|
|||
NMSettingIP6ConfigPrivacy ip6_privacy;
|
||||
NMSettingIP6ConfigAddrGenMode addr_gen_mode;
|
||||
char *token;
|
||||
char *dhcp_duid;
|
||||
} NMSettingIP6ConfigPrivate;
|
||||
|
||||
enum {
|
||||
|
|
@ -68,6 +70,7 @@ enum {
|
|||
PROP_IP6_PRIVACY,
|
||||
PROP_ADDR_GEN_MODE,
|
||||
PROP_TOKEN,
|
||||
PROP_DHCP_DUID,
|
||||
|
||||
LAST_PROP
|
||||
};
|
||||
|
|
@ -141,6 +144,26 @@ nm_setting_ip6_config_get_token (NMSettingIP6Config *setting)
|
|||
return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_setting_ip6_config_get_dhcp_duid:
|
||||
* @setting: the #NMSettingIP6Config
|
||||
*
|
||||
* Returns the value contained in the #NMSettingIP6Config:dhcp-duid
|
||||
* property.
|
||||
*
|
||||
* Returns: The configured DUID value to be included in the DHCPv6 requests
|
||||
* sent to the DHCPv6 servers.
|
||||
*
|
||||
* Since: 1.12
|
||||
**/
|
||||
const char *
|
||||
nm_setting_ip6_config_get_dhcp_duid (NMSettingIP6Config *setting)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_SETTING_IP6_CONFIG (setting), NULL);
|
||||
|
||||
return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->dhcp_duid;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
verify (NMSetting *setting, NMConnection *connection, GError **error)
|
||||
{
|
||||
|
|
@ -254,6 +277,17 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
|
|||
}
|
||||
}
|
||||
|
||||
if (priv->dhcp_duid) {
|
||||
if (!_nm_utils_dhcp_duid_valid (priv->dhcp_duid, NULL)) {
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
||||
_("invalid DUID"));
|
||||
g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP6_CONFIG_DHCP_DUID);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Failures from here on, are NORMALIZABLE_ERROR... */
|
||||
|
||||
if (token_needs_normalization) {
|
||||
|
|
@ -467,6 +501,10 @@ set_property (GObject *object, guint prop_id,
|
|||
g_free (priv->token);
|
||||
priv->token = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_DHCP_DUID:
|
||||
g_free (priv->dhcp_duid);
|
||||
priv->dhcp_duid = g_value_dup_string (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
@ -489,6 +527,9 @@ get_property (GObject *object, guint prop_id,
|
|||
case PROP_TOKEN:
|
||||
g_value_set_string (value, priv->token);
|
||||
break;
|
||||
case PROP_DHCP_DUID:
|
||||
g_value_set_string (value, priv->dhcp_duid);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
@ -502,6 +543,7 @@ finalize (GObject *object)
|
|||
NMSettingIP6ConfigPrivate *priv = NM_SETTING_IP6_CONFIG_GET_PRIVATE (self);
|
||||
|
||||
g_free (priv->token);
|
||||
g_free (priv->dhcp_duid);
|
||||
|
||||
G_OBJECT_CLASS (nm_setting_ip6_config_parent_class)->finalize (object);
|
||||
}
|
||||
|
|
@ -790,6 +832,47 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class)
|
|||
NM_SETTING_PARAM_INFERRABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* NMSettingIP6Config:dhcp-duid:
|
||||
*
|
||||
* A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp
|
||||
* client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried
|
||||
* in the Client Identifier option.
|
||||
* If the property is a hex string ('aa:bb:cc') it is interpreted as a binary
|
||||
* DUID and filled as an opaque value in the Client Identifier option.
|
||||
*
|
||||
* The special value "lease" will retrieve the DUID previously used from the
|
||||
* lease file belonging to the connection. If no DUID is found and "dhclient"
|
||||
* is the configured dhcp client, the DUID is searched in the system-wide
|
||||
* dhclient lease file. If still no DUID is found, or another dhcp client is
|
||||
* used, a global and permanent DUID-UUID (RFC 6355) will be generated based
|
||||
* on the machine-id.
|
||||
*
|
||||
* The special values "llt" and "ll" will generate a DUID of type LLT or LL
|
||||
* (see RFC 3315) based on the current MAC address of the device. In order to
|
||||
* try providing a stable DUID-LLT, the time field will contain a constant
|
||||
* timestamp that is used globally (for all profiles) and persisted to disk.
|
||||
*
|
||||
* The special values "stable-llt", "stable-ll" and "stable-uuid" will generate
|
||||
* a DUID of the corresponding type, derived from the connection's stable-id and
|
||||
* a per-host unique key.
|
||||
* So, the link-layer address of "stable-ll" and "stable-llt" will be a generated
|
||||
* address derived from the stable id. The DUID-LLT time value in the "stable-llt"
|
||||
* option will be picked among a static timespan of three years (the upper bound
|
||||
* of the interval is the same constant timestamp used in "llt").
|
||||
*
|
||||
* When the property is unset, the global value provided for "ipv6.dhcp-duid" is
|
||||
* used. If no global value is provided, the default "lease" value is assumed.
|
||||
*
|
||||
* Since: 1.12
|
||||
**/
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_DHCP_DUID,
|
||||
g_param_spec_string (NM_SETTING_IP6_CONFIG_DHCP_DUID, "", "",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/* IP6-specific property overrides */
|
||||
|
||||
/* ---dbus---
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ G_BEGIN_DECLS
|
|||
|
||||
#define NM_SETTING_IP6_CONFIG_TOKEN "token"
|
||||
|
||||
#define NM_SETTING_IP6_CONFIG_DHCP_DUID "dhcp-duid"
|
||||
|
||||
/**
|
||||
* NM_SETTING_IP6_CONFIG_METHOD_IGNORE:
|
||||
*
|
||||
|
|
@ -162,6 +164,8 @@ NM_AVAILABLE_IN_1_2
|
|||
NMSettingIP6ConfigAddrGenMode nm_setting_ip6_config_get_addr_gen_mode (NMSettingIP6Config *setting);
|
||||
NM_AVAILABLE_IN_1_4
|
||||
const char *nm_setting_ip6_config_get_token (NMSettingIP6Config *setting);
|
||||
NM_AVAILABLE_IN_1_12
|
||||
const char *nm_setting_ip6_config_get_dhcp_duid (NMSettingIP6Config *setting);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
|||
|
|
@ -4436,6 +4436,52 @@ _nm_utils_inet6_is_token (const struct in6_addr *in6addr)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* _nm_utils_dhcp_duid_valid:
|
||||
* @duid: the candidate DUID
|
||||
*
|
||||
* Checks if @duid string contains either a special duid value ("ll",
|
||||
* "llt", "lease" or the "stable" variants) or a valid hex DUID.
|
||||
*
|
||||
* Return value: %TRUE or %FALSE
|
||||
*/
|
||||
gboolean
|
||||
_nm_utils_dhcp_duid_valid (const char *duid, GBytes **out_duid_bin)
|
||||
{
|
||||
gsize duid_len;
|
||||
gs_unref_bytes GBytes *duid_bin = NULL;
|
||||
|
||||
if (out_duid_bin)
|
||||
*out_duid_bin = NULL;
|
||||
|
||||
if (!duid)
|
||||
return FALSE;
|
||||
|
||||
if (NM_IN_STRSET (duid, "lease",
|
||||
"llt",
|
||||
"ll",
|
||||
"stable-llt",
|
||||
"stable-ll",
|
||||
"stable-uuid")) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
duid_bin = nm_utils_hexstr2bin (duid);
|
||||
if (!duid_bin)
|
||||
return FALSE;
|
||||
|
||||
duid_len = g_bytes_get_size (duid_bin);
|
||||
/* MAX DUID lenght is 128 octects + the type code (2 octects). */
|
||||
if ( duid_len <= 2
|
||||
|| duid_len > (128 + 2))
|
||||
return FALSE;
|
||||
|
||||
if (out_duid_bin)
|
||||
*out_duid_bin = g_steal_pointer (&duid_bin);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_utils_check_virtual_device_compatibility:
|
||||
* @virtual_type: a virtual connection type
|
||||
|
|
|
|||
|
|
@ -1355,6 +1355,7 @@ global:
|
|||
nm_setting_connection_get_mdns;
|
||||
nm_setting_connection_mdns_get_type;
|
||||
nm_setting_ip_tunnel_get_flags;
|
||||
nm_setting_ip6_config_get_dhcp_duid;
|
||||
nm_setting_vpn_get_data_keys;
|
||||
nm_setting_vpn_get_secret_keys;
|
||||
nm_setting_wireless_security_get_fils;
|
||||
|
|
|
|||
|
|
@ -704,6 +704,10 @@ ipv6.ip6-privacy=0
|
|||
removes extraneous routes from the tables.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>ipv6.dhcp-duid</varname></term>
|
||||
<listitem><para>If left unspecified, it defaults to "lease".</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>ipv6.dhcp-timeout</varname></term>
|
||||
<listitem><para>If left unspecified, the default value for
|
||||
|
|
|
|||
|
|
@ -37,8 +37,11 @@
|
|||
#include <linux/if_arp.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "nm-utils/nm-dedup-multi.h"
|
||||
#include "nm-utils/nm-random-utils.h"
|
||||
#include "nm-utils/unaligned.h"
|
||||
|
||||
#include "nm-common-macros.h"
|
||||
#include "nm-device-private.h"
|
||||
|
|
@ -7679,12 +7682,203 @@ dhcp6_prefix_delegated (NMDhcpClient *client,
|
|||
g_signal_emit (self, signals[IP6_PREFIX_DELEGATED], 0, prefix);
|
||||
}
|
||||
|
||||
/* RFC 3315 defines the epoch for the DUID-LLT time field on Jan 1st 2000. */
|
||||
#define EPOCH_DATETIME_200001010000 946684800
|
||||
|
||||
static GBytes *
|
||||
generate_duid_llt (const guint8 *hwaddr /* ETH_ALEN bytes */,
|
||||
gint64 time)
|
||||
{
|
||||
GByteArray *duid_arr;
|
||||
const guint16 duid_type = htons (1);
|
||||
const guint16 hw_type = htons (ARPHRD_ETHER);
|
||||
const guint32 duid_time = htonl (NM_MAX (0, time - EPOCH_DATETIME_200001010000));
|
||||
|
||||
duid_arr = g_byte_array_sized_new (2 + 4 + 2 + ETH_ALEN);
|
||||
|
||||
g_byte_array_append (duid_arr, (const guint8 *) &duid_type, 2);
|
||||
g_byte_array_append (duid_arr, (const guint8 *) &hw_type, 2);
|
||||
g_byte_array_append (duid_arr, (const guint8 *) &duid_time, 4);
|
||||
g_byte_array_append (duid_arr, hwaddr, ETH_ALEN);
|
||||
|
||||
return g_byte_array_free_to_bytes (duid_arr);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
generate_duid_ll (const guint8 *hwaddr /* ETH_ALEN bytes */)
|
||||
{
|
||||
GByteArray *duid_arr;
|
||||
const guint16 duid_type = htons (3);
|
||||
const guint16 hw_type = htons (ARPHRD_ETHER);
|
||||
gs_unref_bytes GBytes *stable_hwaddr = NULL;
|
||||
|
||||
duid_arr = g_byte_array_sized_new (2 + 2 + ETH_ALEN);
|
||||
|
||||
g_byte_array_append (duid_arr, (const guint8 *) &duid_type, 2);
|
||||
g_byte_array_append (duid_arr, (const guint8 *) &hw_type, 2);
|
||||
g_byte_array_append (duid_arr, hwaddr, ETH_ALEN);
|
||||
|
||||
return g_byte_array_free_to_bytes (duid_arr);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
generate_duid_uuid (guint8 *data, gsize data_len)
|
||||
{
|
||||
const guint16 duid_type = g_htons (4);
|
||||
const int DUID_SIZE = 18;
|
||||
guint8 *duid_buffer;
|
||||
|
||||
nm_assert (data);
|
||||
nm_assert (data_len >= 16);
|
||||
|
||||
/* Generate a DHCP Unique Identifier for DHCPv6 using the
|
||||
* DUID-UUID method (see RFC 6355 section 4). Format is:
|
||||
*
|
||||
* u16: type (DUID-UUID = 4)
|
||||
* u8[16]: UUID bytes
|
||||
*/
|
||||
duid_buffer = g_malloc (DUID_SIZE);
|
||||
|
||||
G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2);
|
||||
memcpy (&duid_buffer[0], &duid_type, 2);
|
||||
|
||||
/* UUID is 128 bits, we just take the first 128 bits
|
||||
* (regardless of data size) as the DUID-UUID.
|
||||
*/
|
||||
memcpy (&duid_buffer[2], data, 16);
|
||||
|
||||
return g_bytes_new_take (duid_buffer, DUID_SIZE);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcpDuidEnforce *out_enforce)
|
||||
{
|
||||
NMSettingIPConfig *s_ip6;
|
||||
const char *duid;
|
||||
gs_free char *duid_default = NULL;
|
||||
const char *duid_error = NULL;
|
||||
GBytes *duid_out = NULL;
|
||||
guint8 sha256_digest[32];
|
||||
gsize len = sizeof (sha256_digest);
|
||||
|
||||
NM_SET_OUT (out_enforce, NM_DHCP_DUID_ENFORCE_NEVER);
|
||||
|
||||
s_ip6 = nm_connection_get_setting_ip6_config (connection);
|
||||
duid = nm_setting_ip6_config_get_dhcp_duid (NM_SETTING_IP6_CONFIG (s_ip6));
|
||||
|
||||
if (!duid) {
|
||||
duid_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
|
||||
"ipv6.dhcp-duid", self);
|
||||
duid = duid_default;
|
||||
}
|
||||
|
||||
if (!duid || nm_streq (duid, "lease"))
|
||||
return NULL;
|
||||
|
||||
if (!_nm_utils_dhcp_duid_valid (duid, &duid_out))
|
||||
return NULL;
|
||||
|
||||
if (duid_out)
|
||||
return duid_out;
|
||||
|
||||
if (NM_IN_STRSET (duid, "ll", "llt")) {
|
||||
if (!hwaddr) {
|
||||
duid_error = "missing link-layer address";
|
||||
goto end;
|
||||
}
|
||||
if (g_bytes_get_size (hwaddr) != ETH_ALEN) {
|
||||
duid_error = "unsupported link-layer address";
|
||||
goto end;
|
||||
}
|
||||
} else if (NM_IN_STRSET (duid, "stable-llt", "stable-ll", "stable-uuid")) {
|
||||
NMUtilsStableType stable_type;
|
||||
const char *stable_id = NULL;
|
||||
guint32 salted_header;
|
||||
GChecksum *sum;
|
||||
const guint8 *secret_key;
|
||||
gsize secret_key_len;
|
||||
|
||||
stable_id = _get_stable_id (self, connection, &stable_type);
|
||||
if (!stable_id) {
|
||||
nm_assert_not_reached ();
|
||||
duid_error = "cannot retrieve the stable id";
|
||||
goto end;
|
||||
}
|
||||
|
||||
salted_header = htonl (670531087 + stable_type);
|
||||
|
||||
nm_utils_secret_key_get (&secret_key, &secret_key_len);
|
||||
|
||||
sum = g_checksum_new (G_CHECKSUM_SHA256);
|
||||
|
||||
g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header));
|
||||
g_checksum_update (sum, (const guchar *) stable_id, -1);
|
||||
g_checksum_update (sum, (const guchar *) secret_key, secret_key_len);
|
||||
|
||||
g_checksum_get_digest (sum, sha256_digest, &len);
|
||||
g_checksum_free (sum);
|
||||
}
|
||||
|
||||
NM_SET_OUT (out_enforce, NM_DHCP_DUID_ENFORCE_ALWAYS);
|
||||
|
||||
#define EPOCH_DATETIME_THREE_YEARS (356 * 24 * 3600 * 3)
|
||||
if (nm_streq0 (duid, "ll")) {
|
||||
duid_out = generate_duid_ll (g_bytes_get_data (hwaddr, NULL));
|
||||
|
||||
} else if (nm_streq0 (duid, "llt")) {
|
||||
gint64 time;
|
||||
|
||||
time = nm_utils_secret_key_get_timestamp ();
|
||||
if (!time) {
|
||||
duid_error = "cannot retrieve the secret key timestamp";
|
||||
goto end;
|
||||
}
|
||||
|
||||
duid_out = generate_duid_llt (g_bytes_get_data (hwaddr, NULL), time);
|
||||
} else if (nm_streq0 (duid, "stable-ll")) {
|
||||
duid_out = generate_duid_ll (sha256_digest);
|
||||
|
||||
} else if (nm_streq0 (duid, "stable-llt")) {
|
||||
gint64 time;
|
||||
|
||||
/* We want a variable time between the secret_key timestamp and three years
|
||||
* before. Let's compute the time (in seconds) from 0 to 3 years; then we'll
|
||||
* subtract it from the secret_key timestamp.
|
||||
*/
|
||||
time = nm_utils_secret_key_get_timestamp ();
|
||||
if (!time) {
|
||||
duid_error = "cannot retrieve the secret key timestamp";
|
||||
goto end;
|
||||
}
|
||||
/* don't use too old timestamps. They cannot be expressed in DUID-LLT and
|
||||
* would all be truncated to zero. */
|
||||
time = NM_MAX (time, EPOCH_DATETIME_200001010000 + EPOCH_DATETIME_THREE_YEARS);
|
||||
time -= (unaligned_read_be32 (&sha256_digest[ETH_ALEN]) % EPOCH_DATETIME_THREE_YEARS);
|
||||
|
||||
duid_out = generate_duid_llt (sha256_digest, time);
|
||||
|
||||
} else if (nm_streq0 (duid, "stable-uuid")) {
|
||||
duid_out = generate_duid_uuid (sha256_digest, len);
|
||||
}
|
||||
|
||||
end:
|
||||
if (!duid_out) {
|
||||
if (!duid_error)
|
||||
duid_error = "generation failed";
|
||||
_LOGD (LOGD_IP6, "duid-gen (%s): %s. Fallback to 'lease'.", duid, duid_error);
|
||||
}
|
||||
return duid_out;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
NMSettingIPConfig *s_ip6;
|
||||
gs_unref_bytes GBytes *hwaddr = NULL;
|
||||
gs_unref_bytes GBytes *duid = NULL;
|
||||
NMDhcpDuidEnforce enforce_duid;
|
||||
|
||||
const NMPlatformIP6Address *ll_addr = NULL;
|
||||
|
||||
g_assert (connection);
|
||||
|
|
@ -7705,6 +7899,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
|
|||
hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self),
|
||||
nm_device_get_ip_ifindex (self));
|
||||
|
||||
duid = dhcp6_get_duid (self, connection, hwaddr, &enforce_duid);
|
||||
priv->dhcp6.client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (),
|
||||
nm_device_get_multi_index (self),
|
||||
nm_device_get_ip_iface (self),
|
||||
|
|
@ -7716,6 +7911,8 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
|
|||
nm_device_get_route_metric (self, AF_INET6),
|
||||
nm_setting_ip_config_get_dhcp_send_hostname (s_ip6),
|
||||
nm_setting_ip_config_get_dhcp_hostname (s_ip6),
|
||||
duid,
|
||||
enforce_duid,
|
||||
get_dhcp_timeout (self, AF_INET6),
|
||||
priv->dhcp_anycast_address,
|
||||
(priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE,
|
||||
|
|
|
|||
|
|
@ -576,6 +576,8 @@ get_duid (NMDhcpClient *self)
|
|||
|
||||
gboolean
|
||||
nm_dhcp_client_start_ip6 (NMDhcpClient *self,
|
||||
GBytes *client_id,
|
||||
NMDhcpDuidEnforce enforce_duid,
|
||||
const char *dhcp_anycast_addr,
|
||||
const struct in6_addr *ll_addr,
|
||||
const char *hostname,
|
||||
|
|
@ -593,10 +595,23 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
|
|||
g_return_val_if_fail (priv->uuid != NULL, FALSE);
|
||||
|
||||
nm_assert (!priv->duid);
|
||||
/* Read the default DUID for this DHCPv6 client from the
|
||||
* client-specific persistent configuration.
|
||||
*/
|
||||
priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self);
|
||||
|
||||
switch (enforce_duid) {
|
||||
case NM_DHCP_DUID_ENFORCE_NEVER:
|
||||
case NM_DHCP_DUID_ENFORCE_LEASE_FALLBACK:
|
||||
priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self);
|
||||
if (priv->duid)
|
||||
break;
|
||||
/* fall through */
|
||||
case NM_DHCP_DUID_ENFORCE_ALWAYS:
|
||||
if (client_id) {
|
||||
priv->duid = g_bytes_ref (client_id);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
nm_assert_not_reached ();
|
||||
}
|
||||
|
||||
_LOGD ("DUID is '%s'", (str = nm_dhcp_utils_duid_to_string (priv->duid)));
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "nm-setting-ip6-config.h"
|
||||
#include "nm-ip4-config.h"
|
||||
#include "nm-ip6-config.h"
|
||||
#include "nm-dhcp-utils.h"
|
||||
|
||||
#define NM_DHCP_TIMEOUT_DEFAULT ((guint32) 45) /* default DHCP timeout, in seconds */
|
||||
#define NM_DHCP_TIMEOUT_INFINITY G_MAXINT32
|
||||
|
|
@ -149,6 +150,8 @@ gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self,
|
|||
const char *last_ip4_address);
|
||||
|
||||
gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self,
|
||||
GBytes *client_id,
|
||||
NMDhcpDuidEnforce enforce_duid,
|
||||
const char *dhcp_anycast_addr,
|
||||
const struct in6_addr *ll_addr,
|
||||
const char *hostname,
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ client_start (NMDhcpManager *self,
|
|||
guint32 route_metric,
|
||||
const struct in6_addr *ipv6_ll_addr,
|
||||
GBytes *dhcp_client_id,
|
||||
NMDhcpDuidEnforce enforce_duid,
|
||||
guint32 timeout,
|
||||
const char *dhcp_anycast_addr,
|
||||
const char *hostname,
|
||||
|
|
@ -218,7 +219,7 @@ client_start (NMDhcpManager *self,
|
|||
if (addr_family == AF_INET)
|
||||
success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, last_ip4_address);
|
||||
else
|
||||
success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, privacy, needed_prefixes);
|
||||
success = nm_dhcp_client_start_ip6 (client, dhcp_client_id, enforce_duid, dhcp_anycast_addr, ipv6_ll_addr, hostname, privacy, needed_prefixes);
|
||||
|
||||
if (!success) {
|
||||
remove_client_unref (self, client);
|
||||
|
|
@ -280,7 +281,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
|
|||
|
||||
return client_start (self, AF_INET, multi_idx, iface, ifindex, hwaddr, uuid,
|
||||
route_table, route_metric, NULL,
|
||||
dhcp_client_id, timeout, dhcp_anycast_addr, hostname,
|
||||
dhcp_client_id, 0, timeout, dhcp_anycast_addr, hostname,
|
||||
use_fqdn, FALSE, 0, last_ip_address, 0);
|
||||
}
|
||||
|
||||
|
|
@ -297,6 +298,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
|
|||
guint32 route_metric,
|
||||
gboolean send_hostname,
|
||||
const char *dhcp_hostname,
|
||||
GBytes *duid,
|
||||
NMDhcpDuidEnforce enforce_duid,
|
||||
guint32 timeout,
|
||||
const char *dhcp_anycast_addr,
|
||||
gboolean info_only,
|
||||
|
|
@ -314,8 +317,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
|
|||
hostname = dhcp_hostname ?: priv->default_hostname;
|
||||
}
|
||||
return client_start (self, AF_INET6, multi_idx, iface, ifindex, hwaddr, uuid,
|
||||
route_table, route_metric, ll_addr,
|
||||
NULL, timeout, dhcp_anycast_addr, hostname, TRUE, info_only,
|
||||
route_table, route_metric, ll_addr, duid, enforce_duid,
|
||||
timeout, dhcp_anycast_addr, hostname, TRUE, info_only,
|
||||
privacy, NULL, needed_prefixes);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager,
|
|||
guint32 route_metric,
|
||||
gboolean send_hostname,
|
||||
const char *dhcp_hostname,
|
||||
GBytes *duid,
|
||||
NMDhcpDuidEnforce enforce_duid,
|
||||
guint32 timeout,
|
||||
const char *dhcp_anycast_addr,
|
||||
gboolean info_only,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,12 @@
|
|||
#include "nm-ip4-config.h"
|
||||
#include "nm-ip6-config.h"
|
||||
|
||||
typedef enum {
|
||||
NM_DHCP_DUID_ENFORCE_NEVER = 0,
|
||||
NM_DHCP_DUID_ENFORCE_LEASE_FALLBACK,
|
||||
NM_DHCP_DUID_ENFORCE_ALWAYS,
|
||||
} NMDhcpDuidEnforce;
|
||||
|
||||
NMIP4Config *nm_dhcp_utils_ip4_config_from_options (struct _NMDedupMultiIndex *multi_idx,
|
||||
int ifindex,
|
||||
const char *iface,
|
||||
|
|
|
|||
|
|
@ -2896,7 +2896,7 @@ nm_utils_secret_key_get (const guint8 **out_secret_key,
|
|||
return secret_key->is_good;
|
||||
}
|
||||
|
||||
guint64
|
||||
gint64
|
||||
nm_utils_secret_key_get_timestamp (void)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ gboolean nm_utils_machine_id_parse (const char *id_str, /*uuid_t*/ guchar *out_u
|
|||
|
||||
gboolean nm_utils_secret_key_get (const guint8 **out_secret_key,
|
||||
gsize *out_key_len);
|
||||
guint64 nm_utils_secret_key_get_timestamp (void);
|
||||
gint64 nm_utils_secret_key_get_timestamp (void);
|
||||
|
||||
const char *nm_utils_get_boot_id (void);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue