Commit 5f1c1be4 authored by Thomas Haller's avatar Thomas Haller
parents dc3eaaaa 62a78639
......@@ -152,7 +152,7 @@
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently only VPN connections are supported.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SLAVE_TYPE N_("Setting name of the device type of this slave's master connection (eg, \"bond\"), or NULL if this connection is not a slave.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("Token to generate stable IDs for the connection. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. Note that also the interface name of the activating connection and a per-host secret key is included into the address generation so that the same stable-id on different hosts/devices yields different addresses. If the value is unset, an ID unique for the connection is used. Specifying a stable-id allows multiple connections to generate the same addresses. Another use is to generate IDs at runtime via dynamic substitutions. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-boot, or every time. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}/${BOOT}\" to create a unique id for this connection that changes with every reboot. Note that two connections only use the same effective id if their stable-id is also identical before performing dynamic substitutions.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("Token to generate stable IDs for the connection. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable. Note that also the interface name of the activating connection and a per-host secret key is included into the address generation so that the same stable-id on different hosts/devices yields different addresses. If the value is unset, an ID unique for the connection is used. Specifying a stable-id allows multiple connections to generate the same addresses. Another use is to generate IDs at runtime via dynamic substitutions. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-boot, or every time. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}/${BOOT}\" to create a unique id for this connection that changes with every reboot. Note that two connections only use the same effective id if their stable-id is also identical before performing dynamic substitutions.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_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 \"-\").")
......@@ -211,7 +211,7 @@
#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TTL N_("The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES N_("Array of IP addresses.")
#define DESCRIBE_DOC_NM_SETTING_IP4_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 3 seconds). A value greater than zero is a timeout in milliseconds.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values \"mac\" and \"perm-mac\" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet type (01). Currently, these options only work for ethernet type of links. The special value \"stable\" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id). If unset, a globally configure default is used. If still unset, the client-id from the last lease is reused. If unset, a globally configurable default is used. If still unset, the client-id from the last lease may be reused.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_FQDN N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-hostname\" are mutually exclusive and cannot be set at the same time.")
#define DESCRIBE_DOC_NM_SETTING_IP4_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_IP4_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.")
......
......@@ -1541,10 +1541,12 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
* The stable-id is used for generating IPv6 stable private addresses
* with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the
* generated cloned MAC address for ethernet.cloned-mac-address=stable
* and wifi.cloned-mac-address=stable. Note that also the interface name
* of the activating connection and a per-host secret key is included
* into the address generation so that the same stable-id on different
* hosts/devices yields different addresses.
* and wifi.cloned-mac-address=stable. It is also used as DHCP client
* identifier with ipv4.dhcp-client-id=stable.
*
* Note that also the interface name of the activating connection and a
* per-host secret key is included into the address generation so that the
* same stable-id on different hosts/devices yields different addresses.
*
* If the value is unset, an ID unique for the connection is used.
* Specifying a stable-id allows multiple connections to generate the
......
......@@ -719,6 +719,19 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *ip4_class)
* ARP type and the rest is a MAC address).
* If the property is not a hex string it is considered as a
* non-hardware-address client ID and the 'type' field is set to 0.
*
* The special values "mac" and "perm-mac" are supported, which use the
* current or permanent MAC address of the device to generate a client identifier
* with type ethernet type (01). Currently, these options only work for ethernet
* type of links.
*
* The special value "stable" is supported to generate a type 0 client identifier based
* on the stable-id (see connection.stable-id).
*
* If unset, a globally configure default is used. If still unset, the
* client-id from the last lease is reused.
* If unset, a globally configurable default is used. If still unset, the
* client-id from the last lease may be reused.
**/
/* ---ifcfg-rh---
* property: dhcp-client-id
......
......@@ -685,6 +685,9 @@ ipv6.ip6-privacy=0
<varlistentry>
<term><varname>ipv4.dad-timeout</varname></term>
</varlistentry>
<varlistentry>
<term><varname>ipv4.dhcp-client-id</varname></term>
</varlistentry>
<varlistentry>
<term><varname>ipv4.dhcp-timeout</varname></term>
<listitem><para>If left unspecified, the default value for
......
......@@ -34,6 +34,7 @@
#include <arpa/inet.h>
#include <fcntl.h>
#include <linux/if_addr.h>
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
#include <linux/pkt_sched.h>
......@@ -48,6 +49,7 @@
#include "ndisc/nm-ndisc.h"
#include "ndisc/nm-lndp-ndisc.h"
#include "dhcp/nm-dhcp-manager.h"
#include "dhcp/nm-dhcp-utils.h"
#include "nm-act-request.h"
#include "nm-proxy-config.h"
#include "nm-ip4-config.h"
......@@ -5745,8 +5747,7 @@ ipv4_dad_start (NMDevice *self, NMIP4Config **configs, ArpingCallback cb)
ArpingData *data;
guint timeout;
gboolean ret, addr_found;
const guint8 *hw_addr;
size_t hw_addr_len = 0;
const guint8 *hwaddr_arr;
GError *error = NULL;
guint i;
......@@ -5762,13 +5763,12 @@ ipv4_dad_start (NMDevice *self, NMIP4Config **configs, ArpingCallback cb)
}
timeout = get_ipv4_dad_timeout (self);
hw_addr = nm_platform_link_get_address (nm_device_get_platform (self),
nm_device_get_ip_ifindex (self),
&hw_addr_len);
hwaddr_arr = nm_platform_link_get_address (nm_device_get_platform (self),
nm_device_get_ip_ifindex (self),
NULL);
if ( !timeout
|| !hw_addr
|| !hw_addr_len
|| !hwaddr_arr
|| !addr_found
|| nm_device_sys_iface_state_is_external_or_assume (self)) {
......@@ -6394,14 +6394,100 @@ get_dhcp_timeout (NMDevice *self, int addr_family)
return timeout ?: NM_DHCP_TIMEOUT_DEFAULT;
}
static GBytes *
dhcp4_get_client_id (NMDevice *self, NMConnection *connection)
{
NMSettingIPConfig *s_ip4;
const char *client_id;
gs_free char *client_id_default = NULL;
guint8 *client_id_buf;
gboolean is_mac;
s_ip4 = nm_connection_get_setting_ip4_config (connection);
client_id = nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4));
if (!client_id) {
client_id_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
"ipv4.dhcp-client-id", self);
if (client_id_default && client_id_default[0])
client_id = client_id_default;
}
if (!client_id)
return NULL;
if ( (is_mac = nm_streq (client_id, "mac"))
|| nm_streq (client_id, "perm-mac")) {
const char *hwaddr;
char addr_buf[NM_UTILS_HWADDR_LEN_MAX];
gsize addr_len;
guint8 addr_type;
hwaddr = is_mac
? nm_device_get_hw_address (self)
: nm_device_get_permanent_hw_address (self);
if (!hwaddr)
return NULL;
if (!_nm_utils_hwaddr_aton (hwaddr, addr_buf, sizeof (addr_buf), &addr_len))
g_return_val_if_reached (NULL);
switch (addr_len) {
case ETH_ALEN:
addr_type = ARPHRD_ETHER;
break;
default:
/* unsupported type. */
return NULL;
}
client_id_buf = g_malloc (addr_len + 1);
client_id_buf[0] = addr_type;
memcpy (&client_id_buf[1], addr_buf, addr_len);
return g_bytes_new_take (client_id_buf, addr_len + 1);
}
if (nm_streq (client_id, "stable")) {
NMUtilsStableType stable_type;
const char *stable_id;
GChecksum *sum;
guint8 buf[20];
gsize buf_size;
guint32 salted_header;
stable_id = _get_stable_id (self, connection, &stable_type);
if (!stable_id)
g_return_val_if_reached (NULL);
salted_header = htonl (2011610591 + stable_type);
sum = g_checksum_new (G_CHECKSUM_SHA1);
g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header));
g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id));
buf_size = sizeof (buf);
g_checksum_get_digest (sum, buf, &buf_size);
nm_assert (buf_size == sizeof (buf));
g_checksum_free (sum);
client_id_buf = g_malloc (1 + 15);
client_id_buf[0] = 0;
memcpy (&client_id_buf[0], buf, 15);
return g_bytes_new_take (client_id_buf, 1 + 15);
}
return nm_dhcp_utils_client_id_string_to_bytes (client_id);
}
static NMActStageReturn
dhcp4_start (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingIPConfig *s_ip4;
const guint8 *hw_addr;
size_t hw_addr_len = 0;
GByteArray *tmp = NULL;
gs_unref_bytes GBytes *hwaddr = NULL;
gs_unref_bytes GBytes *client_id = NULL;
NMConnection *connection;
connection = nm_device_get_applied_connection (self);
......@@ -6413,33 +6499,28 @@ dhcp4_start (NMDevice *self)
nm_exported_object_clear_and_unexport (&priv->dhcp4.config);
priv->dhcp4.config = nm_dhcp4_config_new ();
hw_addr = nm_platform_link_get_address (nm_device_get_platform (self), nm_device_get_ip_ifindex (self), &hw_addr_len);
if (hw_addr_len) {
tmp = g_byte_array_sized_new (hw_addr_len);
g_byte_array_append (tmp, hw_addr, hw_addr_len);
}
hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self),
nm_device_get_ip_ifindex (self));
client_id = dhcp4_get_client_id (self, connection);
/* Begin DHCP on the interface */
g_warn_if_fail (priv->dhcp4.client == NULL);
priv->dhcp4.client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (),
nm_netns_get_multi_idx (nm_device_get_netns (self)),
nm_device_get_ip_iface (self),
nm_device_get_ip_ifindex (self),
tmp,
hwaddr,
nm_connection_get_uuid (connection),
nm_device_get_route_table (self, AF_INET, TRUE),
nm_device_get_route_metric (self, AF_INET),
nm_setting_ip_config_get_dhcp_send_hostname (s_ip4),
nm_setting_ip_config_get_dhcp_hostname (s_ip4),
nm_setting_ip4_config_get_dhcp_fqdn (NM_SETTING_IP4_CONFIG (s_ip4)),
nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)),
client_id,
get_dhcp_timeout (self, AF_INET),
priv->dhcp_anycast_address,
NULL);
if (tmp)
g_byte_array_free (tmp, TRUE);
if (!priv->dhcp4.client)
return NM_ACT_STAGE_RETURN_FAILURE;
......@@ -7128,9 +7209,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingIPConfig *s_ip6;
GByteArray *tmp = NULL;
const guint8 *hw_addr;
size_t hw_addr_len = 0;
gs_unref_bytes GBytes *hwaddr = NULL;
const NMPlatformIP6Address *ll_addr = NULL;
g_assert (connection);
......@@ -7145,17 +7224,14 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
return FALSE;
}
hw_addr = nm_platform_link_get_address (nm_device_get_platform (self), nm_device_get_ip_ifindex (self), &hw_addr_len);
if (hw_addr_len) {
tmp = g_byte_array_sized_new (hw_addr_len);
g_byte_array_append (tmp, hw_addr, hw_addr_len);
}
hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self),
nm_device_get_ip_ifindex (self));
priv->dhcp6.client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (),
nm_device_get_multi_index (self),
nm_device_get_ip_iface (self),
nm_device_get_ip_ifindex (self),
tmp,
hwaddr,
&ll_addr->address,
nm_connection_get_uuid (connection),
nm_device_get_route_table (self, AF_INET6, TRUE),
......@@ -7167,8 +7243,6 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
(priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE,
nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)),
priv->dhcp6.needed_prefixes);
if (tmp)
g_byte_array_free (tmp, TRUE);
if (priv->dhcp6.client) {
priv->dhcp6.state_sigid = g_signal_connect (priv->dhcp6.client,
......
......@@ -52,23 +52,24 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
PROP_MULTI_IDX,
PROP_ADDR_FAMILY,
PROP_FLAGS,
PROP_HWADDR,
PROP_IFACE,
PROP_IFINDEX,
PROP_HWADDR,
PROP_UUID,
PROP_ROUTE_TABLE,
PROP_MULTI_IDX,
PROP_ROUTE_METRIC,
PROP_ROUTE_TABLE,
PROP_TIMEOUT,
PROP_UUID,
);
typedef struct _NMDhcpClientPrivate {
NMDedupMultiIndex *multi_idx;
char * iface;
GByteArray * hwaddr;
GBytes * hwaddr;
char * uuid;
GByteArray * duid;
GBytes * duid;
GBytes * client_id;
char * hostname;
pid_t pid;
......@@ -138,7 +139,7 @@ nm_dhcp_client_get_uuid (NMDhcpClient *self)
return NM_DHCP_CLIENT_GET_PRIVATE (self)->uuid;
}
const GByteArray *
GBytes *
nm_dhcp_client_get_duid (NMDhcpClient *self)
{
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
......@@ -146,7 +147,7 @@ nm_dhcp_client_get_duid (NMDhcpClient *self)
return NM_DHCP_CLIENT_GET_PRIVATE (self)->duid;
}
const GByteArray *
GBytes *
nm_dhcp_client_get_hw_addr (NMDhcpClient *self)
{
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
......@@ -238,20 +239,6 @@ nm_dhcp_client_set_client_id_bin (NMDhcpClient *self,
_set_client_id (self, b, TRUE);
}
void
nm_dhcp_client_set_client_id_str (NMDhcpClient *self,
const char *dhcp_client_id)
{
g_return_if_fail (NM_IS_DHCP_CLIENT (self));
g_return_if_fail (!dhcp_client_id || dhcp_client_id[0]);
_set_client_id (self,
dhcp_client_id
? nm_dhcp_utils_client_id_string_to_bytes (dhcp_client_id)
: NULL,
TRUE);
}
const char *
nm_dhcp_client_get_hostname (NMDhcpClient *self)
{
......@@ -260,6 +247,14 @@ nm_dhcp_client_get_hostname (NMDhcpClient *self)
return NM_DHCP_CLIENT_GET_PRIVATE (self)->hostname;
}
gboolean
nm_dhcp_client_get_info_only (NMDhcpClient *self)
{
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
return NM_DHCP_CLIENT_GET_PRIVATE (self)->info_only;
}
gboolean
nm_dhcp_client_get_use_fqdn (NMDhcpClient *self)
{
......@@ -345,7 +340,7 @@ nm_dhcp_client_stop_pid (pid_t pid, const char *iface)
}
static void
stop (NMDhcpClient *self, gboolean release, const GByteArray *duid)
stop (NMDhcpClient *self, gboolean release, GBytes *duid)
{
NMDhcpClientPrivate *priv;
......@@ -359,7 +354,6 @@ stop (NMDhcpClient *self, gboolean release, const GByteArray *duid)
nm_dhcp_client_stop_pid (priv->pid, priv->iface);
}
priv->pid = -1;
priv->info_only = FALSE;
}
void
......@@ -492,10 +486,9 @@ nm_dhcp_client_watch_child (NMDhcpClient *self, pid_t pid)
gboolean
nm_dhcp_client_start_ip4 (NMDhcpClient *self,
const char *dhcp_client_id,
GBytes *client_id,
const char *dhcp_anycast_addr,
const char *hostname,
gboolean use_fqdn,
const char *last_ip4_address)
{
NMDhcpClientPrivate *priv;
......@@ -512,19 +505,19 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self,
else
_LOGI ("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout);
nm_dhcp_client_set_client_id_str (self, dhcp_client_id);
nm_dhcp_client_set_client_id (self, client_id);
g_clear_pointer (&priv->hostname, g_free);
priv->hostname = g_strdup (hostname);
priv->use_fqdn = use_fqdn;
return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address);
}
static GByteArray *
static GBytes *
generate_duid_from_machine_id (void)
{
GByteArray *duid;
const int DUID_SIZE = 18;
guint8 *duid_buffer;
GChecksum *sum;
guint8 buffer[32]; /* SHA256 digest size */
gsize sumlen = sizeof (buffer);
......@@ -532,6 +525,7 @@ generate_duid_from_machine_id (void)
uuid_t uuid;
gs_free char *machine_id_s = NULL;
gs_free char *str = NULL;
GBytes *duid;
machine_id_s = nm_utils_machine_id_read ();
if (nm_utils_machine_id_parse (machine_id_s, uuid)) {
......@@ -554,36 +548,31 @@ generate_duid_from_machine_id (void)
* u16: type (DUID-UUID = 4)
* u8[16]: UUID bytes
*/
duid = g_byte_array_sized_new (18);
g_byte_array_append (duid, (guint8 *) &duid_type, sizeof (duid_type));
duid_buffer = g_malloc (DUID_SIZE);
G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2);
memcpy (&duid_buffer[0], &duid_type, 2);
/* Since SHA256 is 256 bits, but UUID is 128 bits, we just take the first
* 128 bits of the SHA256 as the DUID-UUID.
*/
g_byte_array_append (duid, buffer, 16);
memcpy (&duid_buffer[2], buffer, 16);
duid = g_bytes_new_take (duid_buffer, DUID_SIZE);
nm_log_dbg (LOGD_DHCP, "dhcp: generated DUID %s",
(str = nm_dhcp_utils_duid_to_string (duid)));
return duid;
}
static GByteArray *
static GBytes *
get_duid (NMDhcpClient *self)
{
static GByteArray *duid = NULL;
GByteArray *copy = NULL;
static GBytes *duid = NULL;
if (G_UNLIKELY (duid == NULL)) {
if (G_UNLIKELY (!duid))
duid = generate_duid_from_machine_id ();
g_assert (duid);
}
if (G_LIKELY (duid)) {
copy = g_byte_array_sized_new (duid->len);
g_byte_array_append (copy, duid->data, duid->len);
}
return copy;
return g_bytes_ref (duid);
}
gboolean
......@@ -591,7 +580,6 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
const char *dhcp_anycast_addr,
const struct in6_addr *ll_addr,
const char *hostname,
gboolean info_only,
NMSettingIP6ConfigPrivacy privacy,
guint needed_prefixes)
{
......@@ -616,8 +604,6 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
g_clear_pointer (&priv->hostname, g_free);
priv->hostname = g_strdup (hostname);
priv->info_only = info_only;
if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY)
_LOGI ("activation: beginning transaction (no timeout)");
else
......@@ -626,7 +612,6 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
return NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self,
dhcp_anycast_addr,
ll_addr,
info_only,
privacy,
priv->duid,
needed_prefixes);
......@@ -923,8 +908,16 @@ set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE ((NMDhcpClient *) object);
guint flags;
switch (prop_id) {
case PROP_FLAGS:
/* construct-only */
flags = g_value_get_uint (value);
nm_assert ((flags & ~((guint) (NM_DHCP_CLIENT_FLAGS_INFO_ONLY | NM_DHCP_CLIENT_FLAGS_USE_FQDN))) == 0);
priv->info_only = NM_FLAGS_HAS (flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY);
priv->use_fqdn = NM_FLAGS_HAS (flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN);
break;
case PROP_MULTI_IDX:
/* construct-only */
priv->multi_idx = g_value_get_pointer (value);
......@@ -1008,16 +1001,8 @@ dispose (GObject *object)
g_clear_pointer (&priv->hostname, g_free);
g_clear_pointer (&priv->uuid, g_free);
g_clear_pointer (&priv->client_id, g_bytes_unref);
if (priv->hwaddr) {
g_byte_array_free (priv->hwaddr, TRUE);
priv->hwaddr = NULL;
}
if (priv->duid) {
g_byte_array_free (priv->duid, TRUE);
priv->duid = NULL;
}
g_clear_pointer (&priv->hwaddr, g_bytes_unref);
g_clear_pointer (&priv->duid, g_bytes_unref);
G_OBJECT_CLASS (nm_dhcp_client_parent_class)->dispose (object);
......@@ -1058,7 +1043,7 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
obj_properties[PROP_HWADDR] =
g_param_spec_boxed (NM_DHCP_CLIENT_HWADDR, "", "",
G_TYPE_BYTE_ARRAY,
G_TYPE_BYTES,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
......@@ -1092,6 +1077,12 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_FLAGS] =
g_param_spec_uint (NM_DHCP_CLIENT_FLAGS, "", "",
0, G_MAXUINT32, 0,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
signals[SIGNAL_STATE_CHANGED] =
......
......@@ -34,15 +34,16 @@
#define NM_IS_DHCP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP_CLIENT))
#define NM_DHCP_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass))
#define NM_DHCP_CLIENT_INTERFACE "iface"
#define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family"
#define NM_DHCP_CLIENT_IFINDEX "ifindex"
#define NM_DHCP_CLIENT_HWADDR "hwaddr"
#define NM_DHCP_CLIENT_UUID "uuid"
#define NM_DHCP_CLIENT_ROUTE_TABLE "route-table"
#define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family"
#define NM_DHCP_CLIENT_FLAGS "flags"
#define NM_DHCP_CLIENT_HWADDR "hwaddr"
#define NM_DHCP_CLIENT_IFINDEX "ifindex"
#define NM_DHCP_CLIENT_INTERFACE "iface"
#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx"
#define NM_DHCP_CLIENT_ROUTE_METRIC "route-metric"
#define NM_DHCP_CLIENT_TIMEOUT "timeout"
#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx"
#define NM_DHCP_CLIENT_ROUTE_TABLE "route-table"
#define NM_DHCP_CLIENT_TIMEOUT "timeout"
#define NM_DHCP_CLIENT_UUID "uuid"
#define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed"
#define NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED "prefix-delegated"
......@@ -67,6 +68,11 @@ typedef struct {
CList dhcp_client_lst;
} NMDhcpClient;
typedef enum {
NM_DHCP_CLIENT_FLAGS_INFO_ONLY = (1LL << 0),
NM_DHCP_CLIENT_FLAGS_USE_FQDN = (1LL << 1),
} NMDhcpClientFlags;
typedef struct {
GObjectClass parent;
......@@ -79,14 +85,13 @@ typedef struct {
gboolean (*ip6_start) (NMDhcpClient *self,
const char *anycast_addr,
const struct in6_addr *ll_addr,
gboolean info_only,
NMSettingIP6ConfigPrivacy privacy,
const GByteArray *duid,
GBytes *duid,
guint needed_prefixes);
void (*stop) (NMDhcpClient *self,
gboolean release,
const GByteArray *duid);
GBytes *duid);
/**
* get_duid:
......@@ -97,7 +102,7 @@ typedef struct {
* representation of the DUID. If no DUID is found, %NULL should be
* returned.
*/
GByteArray * (*get_duid) (NMDhcpClient *self);
GBytes *(*get_duid) (NMDhcpClient *self);
/* Signals */
void (*state_changed) (NMDhcpClient *self,
......@@ -120,9 +125,9 @@ int nm_dhcp_client_get_ifindex (NMDhcpClient *self);
const char *nm_dhcp_client_get_uuid (NMDhcpClient *self);
const GByteArray *nm_dhcp_client_get_duid (NMDhcpClient *self);
GBytes *nm_dhcp_client_get_duid (NMDhcpClient *self);
const GByteArray *nm_dhcp_client_get_hw_addr (NMDhcpClient *self);
GBytes *nm_dhcp_client_get_hw_addr (NMDhcpClient *self);
guint32 nm_dhcp_client_get_route_table (NMDhcpClient *self);
......@@ -134,20 +139,20 @@ GBytes *nm_dhcp_client_get_client_id (NMDhcpClient *self);
const char *nm_dhcp_client_get_hostname (NMDhcpClient *self);
gboolean nm_dhcp_client_get_info_only (NMDhcpClient *self);
gboolean nm_dhcp_client_get_use_fqdn (NMDhcpClient *self);
gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self,
const char *dhcp_client_id,
GBytes *client_id,
const char *dhcp_anycast_addr,
const char *hostname,
gboolean use_fqdn,
const char *last_ip4_address);
gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self,
const char *dhcp_anycast_addr,
const struct in6_addr *ll_addr,
const char *hostname,
gboolean info_only,
NMSettingIP6ConfigPrivacy privacy,
guint needed_prefixes);
......@@ -180,8 +185,6 @@ void nm_dhcp_client_set_client_id_bin (NMDhcpClient *self,
guint8 type,
const guint8 *client_id,
gsize len);
void nm_dhcp_client_set_client_id_str (NMDhcpClient *self,
const char *dhcp_client_id);
/*****************************************************************************
* Client data
......
......@@ -279,6 +279,7 @@ nm_dhcp_dhclient_create_config (const char *interface,
g_return_val_if_fail (!anycast_addr || nm_utils_hwaddr_valid (anycast_addr, ETH_ALEN), NULL);
g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), NULL);
nm_assert (!out_new_client_id || !*out_new_client_id);
new_contents = g_string_new (_("# Created by NetworkManager\n"));
fqdn_opts = g_ptr_array_sized_new (5);
......@@ -332,6 +333,8 @@ nm_dhcp_dhclient_create_config (const char *interface,
continue;
/* Otherwise capture and return the existing client id */
if (out_new_client_id)
g_clear_pointer (out_new_client_id, g_bytes_unref);
NM_SET_OUT (out_new_client_id, read_client_id (p));
}
......@@ -444,14 +447,20 @@ nm_dhcp_dhclient_create_config (const char *interface,
/* Roughly follow what dhclient's quotify_buf() and pretty_escape() functions do */
char *
nm_dhcp_dhclient_escape_duid (const GByteArray *duid)
nm_dhcp_dhclient_escape_duid (GBytes *duid)
{
char *escaped;
const guint8 *s = duid->data;
const guint8 *s, *s0;
gsize len;
char *d;
d = escaped = g_malloc0 ((duid->len * 4) + 1);
while (s < (duid->data + duid->len)) {
g_return_val_if_fail (duid, NULL);
s0 = g_bytes_get_data (duid, &len);
s = s0;
d = escaped = g_malloc ((len * 4) + 1);
while (s < (s0 + len)) {
if (!g_ascii_isprint (*s)) {
*d++ = '\\';
*d++ = '0' + ((*s >> 6) & 0x7);
......@@ -465,6 +474,7 @@ nm_dhcp_dhclient_escape_duid (const GByteArray *duid)
} else
*d++ = *s++;
}
*d++ = '\0';
return escaped;
}
......@@ -476,7 +486,7 @@ isoctal (const guint8 *p)
&& p[2] >= '0' && p[2] <= '7');
}
GByteArray *
GBytes *
nm_dhcp_dhclient_unescape_duid (const char *duid)
{
GByteArray *unescaped;
......@@ -507,7 +517,7 @@ nm_dhcp_dhclient_unescape_duid (const char *duid)
g_byte_array_append (unescaped, &p[i], 1);
}
return unescaped;
return g_byte_array_free_to_bytes (unescaped);
error:
g_byte_array_free (unescaped, TRUE);
......@@ -516,10 +526,10 @@ error: