core: support ipvX.dhcp-iaid properties

This commit is contained in:
Beniamino Galvani
2019-10-15 14:45:47 +02:00
parent 56a1a5426a
commit 6f16e524be
11 changed files with 210 additions and 32 deletions

View File

@@ -712,6 +712,10 @@ ipv6.ip6-privacy=0
<varlistentry>
<term><varname>ipv4.dhcp-client-id</varname></term>
</varlistentry>
<varlistentry>
<term><varname>ipv4.dhcp-iaid</varname></term>
<listitem><para>If left unspecified, it defaults to "ifname".</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ipv4.dhcp-timeout</varname></term>
<listitem><para>If left unspecified, the default value for
@@ -736,6 +740,10 @@ ipv6.ip6-privacy=0
<term><varname>ipv6.dhcp-duid</varname></term>
<listitem><para>If left unspecified, it defaults to "lease".</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ipv6.dhcp-iaid</varname></term>
<listitem><para>If left unspecified, it defaults to "ifname".</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ipv6.dhcp-timeout</varname></term>
<listitem><para>If left unspecified, the default value for

View File

@@ -7905,6 +7905,121 @@ get_dhcp_timeout (NMDevice *self, int addr_family)
return timeout ?: NM_DHCP_TIMEOUT_DEFAULT;
}
/**
* dhcp_get_iaid:
* @self: the #NMDevice
* @addr_family: the address family
* @connection: the connection
* @out_is_explicit: on return, %TRUE if the user set a valid IAID in
* the connection or in global configuration; %FALSE if the connection
* property was empty and no valid global configuration was provided.
*
* Returns: a IAID value for this device and the given connection.
*/
static guint32
dhcp_get_iaid (NMDevice *self,
int addr_family,
NMConnection *connection,
gboolean *out_is_explicit)
{
NMSettingIPConfig *s_ip;
const char *iaid_str;
gs_free char *iaid_str_free = NULL;
guint32 iaid;
const char *iface;
const char *fail_reason;
gboolean is_explicit = TRUE;
s_ip = nm_connection_get_setting_ip_config (connection, addr_family);
iaid_str = nm_setting_ip_config_get_dhcp_iaid (s_ip);
if (!iaid_str) {
iaid_str_free = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
addr_family == AF_INET
? NM_CON_DEFAULT ("ipv4.dhcp-iaid")
: NM_CON_DEFAULT ("ipv6.dhcp-iaid"),
self);
iaid_str = iaid_str_free;
if (!iaid_str) {
iaid_str = NM_IAID_IFNAME;
is_explicit = FALSE;
} else if (!_nm_utils_iaid_verify (iaid_str, NULL)) {
_LOGW (LOGD_DEVICE, "invalid global default '%s' for ipv%c.dhcp-iaid",
iaid_str,
nm_utils_addr_family_to_char (addr_family));
iaid_str = NM_IAID_IFNAME;
is_explicit = FALSE;
}
}
if (nm_streq0 (iaid_str, NM_IAID_MAC)) {
const NMPlatformLink *pllink;
pllink = nm_platform_link_get (nm_device_get_platform (self),
nm_device_get_ip_ifindex (self));
if (!pllink || pllink->l_address.len < 4) {
fail_reason = "invalid link-layer address";
goto out_fail;
}
/* @iaid is in native endianness. Use unaligned_read_be32()
* so that the IAID for a given MAC address is the same on
* BE and LE machines. */
iaid = unaligned_read_be32 (&pllink->l_address.data[pllink->l_address.len - 4]);
goto out_good;
} else if (nm_streq0 (iaid_str, NM_IAID_PERM_MAC)) {
guint8 hwaddr_buf[NM_UTILS_HWADDR_LEN_MAX];
const char *hwaddr_str;
gsize hwaddr_len;
hwaddr_str = nm_device_get_permanent_hw_address (self);
if (!hwaddr_str) {
fail_reason = "no permanent link-layer address";
goto out_fail;
}
if (!_nm_utils_hwaddr_aton (hwaddr_str, hwaddr_buf, sizeof (hwaddr_buf), &hwaddr_len))
g_return_val_if_reached (0);
if (hwaddr_len < 4) {
fail_reason = "invalid link-layer address";
goto out_fail;
}
iaid = unaligned_read_be32 (&hwaddr_buf[hwaddr_len - 4]);
goto out_good;
} else if ((iaid = _nm_utils_ascii_str_to_int64 (iaid_str, 10, 0, G_MAXUINT32, -1)) != -1) {
goto out_good;
} else {
iface = nm_device_get_ip_iface (self);
iaid = nm_utils_create_dhcp_iaid (TRUE,
(const guint8 *) iface,
strlen (iface));
goto out_good;
}
out_fail:
nm_assert (fail_reason);
_LOGW ( addr_family == AF_INET
? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4)
: (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6),
"ipv%c.dhcp-iaid: failure to generate IAID: %s. Using interface-name based IAID",
nm_utils_addr_family_to_char (addr_family), fail_reason);
is_explicit = FALSE;
iface = nm_device_get_ip_iface (self);
iaid = nm_utils_create_dhcp_iaid (TRUE,
(const guint8 *) iface,
strlen (iface));
out_good:
_LOGD ( addr_family == AF_INET
? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4)
: (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6),
"ipv%c.dhcp-iaid: using %u (0x%08x) IAID (str: '%s', explicit %d)",
nm_utils_addr_family_to_char (addr_family), iaid, iaid,
iaid_str, is_explicit);
NM_SET_OUT (out_is_explicit, is_explicit);
return iaid;
}
static GBytes *
dhcp4_get_client_id (NMDevice *self,
NMConnection *connection,
@@ -7981,8 +8096,10 @@ dhcp4_get_client_id (NMDevice *self,
}
if (nm_streq (client_id, "duid")) {
guint32 iaid = dhcp_get_iaid (self, AF_INET, connection, NULL);
result = nm_utils_dhcp_client_id_systemd_node_specific (TRUE,
nm_device_get_ip_iface (self));
iaid);
goto out_good;
}
@@ -8848,6 +8965,8 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
gboolean enforce_duid = FALSE;
const NMPlatformLink *pllink;
GError *error = NULL;
guint32 iaid;
gboolean iaid_explicit;
const NMPlatformIP6Address *ll_addr = NULL;
@@ -8872,6 +8991,8 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
bcast_hwaddr = nmp_link_address_get_as_bytes (&pllink->l_broadcast);
}
iaid = dhcp_get_iaid (self, AF_INET6, connection, &iaid_explicit);
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),
@@ -8887,6 +9008,8 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
nm_setting_ip_config_get_dhcp_hostname (s_ip6),
duid,
enforce_duid,
iaid,
iaid_explicit,
get_dhcp_timeout (self, AF_INET6),
priv->dhcp_anycast_address,
(priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE,

View File

@@ -46,6 +46,8 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDhcpClient,
PROP_ROUTE_TABLE,
PROP_TIMEOUT,
PROP_UUID,
PROP_IAID,
PROP_IAID_EXPLICIT,
PROP_HOSTNAME,
);
@@ -65,9 +67,11 @@ typedef struct _NMDhcpClientPrivate {
guint32 route_table;
guint32 route_metric;
guint32 timeout;
guint32 iaid;
NMDhcpState state;
bool info_only:1;
bool use_fqdn:1;
bool iaid_explicit:1;
} NMDhcpClientPrivate;
G_DEFINE_ABSTRACT_TYPE (NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT)
@@ -186,6 +190,22 @@ nm_dhcp_client_get_timeout (NMDhcpClient *self)
return NM_DHCP_CLIENT_GET_PRIVATE (self)->timeout;
}
guint32
nm_dhcp_client_get_iaid (NMDhcpClient *self)
{
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), 0);
return NM_DHCP_CLIENT_GET_PRIVATE (self)->iaid;
}
gboolean
nm_dhcp_client_get_iaid_explicit (NMDhcpClient *self)
{
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
return NM_DHCP_CLIENT_GET_PRIVATE (self)->iaid_explicit;
}
GBytes *
nm_dhcp_client_get_client_id (NMDhcpClient *self)
{
@@ -928,6 +948,12 @@ get_property (GObject *object, guint prop_id,
case PROP_UUID:
g_value_set_string (value, priv->uuid);
break;
case PROP_IAID:
g_value_set_uint (value, priv->iaid);
break;
case PROP_IAID_EXPLICIT:
g_value_set_boolean (value, priv->iaid_explicit);
break;
case PROP_HOSTNAME:
g_value_set_string (value, priv->hostname);
break;
@@ -997,6 +1023,14 @@ set_property (GObject *object, guint prop_id,
/* construct-only */
priv->uuid = g_value_dup_string (value);
break;
case PROP_IAID:
/* construct-only */
priv->iaid = g_value_get_uint (value);
break;
case PROP_IAID_EXPLICIT:
/* construct-only */
priv->iaid_explicit = g_value_get_boolean (value);
break;
case PROP_HOSTNAME:
/* construct-only */
priv->hostname = g_value_dup_string (value);
@@ -1116,6 +1150,18 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_IAID] =
g_param_spec_uint (NM_DHCP_CLIENT_IAID, "", "",
0, G_MAXUINT32, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_IAID_EXPLICIT] =
g_param_spec_boolean (NM_DHCP_CLIENT_IAID_EXPLICIT, "", "",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_HOSTNAME] =
g_param_spec_string (NM_DHCP_CLIENT_HOSTNAME, "", "",
NULL,

View File

@@ -34,6 +34,8 @@
#define NM_DHCP_CLIENT_ROUTE_TABLE "route-table"
#define NM_DHCP_CLIENT_TIMEOUT "timeout"
#define NM_DHCP_CLIENT_UUID "uuid"
#define NM_DHCP_CLIENT_IAID "iaid"
#define NM_DHCP_CLIENT_IAID_EXPLICIT "iaid-explicit"
#define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed"
#define NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED "prefix-delegated"
@@ -130,6 +132,10 @@ void nm_dhcp_client_set_route_metric (NMDhcpClient *self, guint32 route_metric);
guint32 nm_dhcp_client_get_timeout (NMDhcpClient *self);
guint32 nm_dhcp_client_get_iaid (NMDhcpClient *self);
gboolean nm_dhcp_client_get_iaid_explicit (NMDhcpClient *self);
GBytes *nm_dhcp_client_get_client_id (NMDhcpClient *self);
const char *nm_dhcp_client_get_hostname (NMDhcpClient *self);

View File

@@ -522,6 +522,9 @@ ip6_start (NMDhcpClient *client,
NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client);
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self);
if (nm_dhcp_client_get_iaid_explicit (client))
_LOGW ("dhclient does not support specifying an IAID for DHCPv6, it will be ignored");
priv->conf_file = create_dhclient_config (self,
AF_INET6,
nm_dhcp_client_get_iface (client),

View File

@@ -213,6 +213,8 @@ client_start (NMDhcpManager *self,
const struct in6_addr *ipv6_ll_addr,
GBytes *dhcp_client_id,
gboolean enforce_duid,
guint32 iaid,
gboolean iaid_explicit,
guint32 timeout,
const char *dhcp_anycast_addr,
const char *hostname,
@@ -297,6 +299,8 @@ client_start (NMDhcpManager *self,
NM_DHCP_CLIENT_HWADDR, hwaddr,
NM_DHCP_CLIENT_BROADCAST_HWADDR, bcast_hwaddr,
NM_DHCP_CLIENT_UUID, uuid,
NM_DHCP_CLIENT_IAID, (guint) iaid,
NM_DHCP_CLIENT_IAID_EXPLICIT, iaid_explicit,
NM_DHCP_CLIENT_HOSTNAME, hostname,
NM_DHCP_CLIENT_ROUTE_TABLE, (guint) route_table,
NM_DHCP_CLIENT_ROUTE_METRIC, (guint) route_metric,
@@ -426,6 +430,8 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
NULL,
dhcp_client_id,
FALSE,
0,
FALSE,
timeout,
dhcp_anycast_addr,
hostname,
@@ -453,6 +459,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
const char *dhcp_hostname,
GBytes *duid,
gboolean enforce_duid,
guint32 iaid,
gboolean iaid_explicit,
guint32 timeout,
const char *dhcp_anycast_addr,
gboolean info_only,
@@ -483,6 +491,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
ll_addr,
duid,
enforce_duid,
iaid,
iaid_explicit,
timeout,
dhcp_anycast_addr,
hostname,

View File

@@ -62,6 +62,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager,
const char *dhcp_hostname,
GBytes *duid,
gboolean enforce_duid,
guint32 iaid,
gboolean iaid_explicit,
guint32 timeout,
const char *dhcp_anycast_addr,
gboolean info_only,

View File

@@ -883,7 +883,6 @@ ip6_start (NMDhcpClient *client,
nm_auto (sd_dhcp6_client_unrefp) sd_dhcp6_client *sd_client = NULL;
GBytes *hwaddr;
const char *hostname;
const char *iface;
int r, i;
const guint8 *duid_arr;
gsize duid_len;
@@ -913,12 +912,8 @@ ip6_start (NMDhcpClient *client,
if (nm_dhcp_client_get_info_only (client))
sd_dhcp6_client_set_information_request (sd_client, 1);
iface = nm_dhcp_client_get_iface (client);
r = sd_dhcp6_client_set_iaid (sd_client,
nm_utils_create_dhcp_iaid (TRUE,
(const guint8 *) iface,
strlen (iface)));
nm_dhcp_client_get_iaid (client));
if (r < 0) {
nm_utils_error_set_errno (error, r, "failed to set IAID: %s");
return FALSE;

View File

@@ -3621,9 +3621,7 @@ nm_utils_create_dhcp_iaid (gboolean legacy_unstable_byteorder,
* @legacy_unstable_byteorder: historically, the code would generate a iaid
* dependent on host endianness. This is undesirable, if backward compatibility
* are not a concern, generate stable endianness.
* @interface_id: a binary identifier that is hashed into the DUID.
* Comonly this is the interface-name, but it may be the MAC address.
* @interface_id_len: the length of @interface_id.
* @iaid: the IAID (identity association identifier) in native byte order
* @machine_id: the binary identifier for the machine. It is hashed
* into the DUID. It commonly is /etc/machine-id (parsed in binary as NMUuid).
* @machine_id_len: the length of the @machine_id.
@@ -3636,8 +3634,7 @@ nm_utils_create_dhcp_iaid (gboolean legacy_unstable_byteorder,
*/
GBytes *
nm_utils_dhcp_client_id_systemd_node_specific_full (gboolean legacy_unstable_byteorder,
const guint8 *interface_id,
gsize interface_id_len,
guint32 iaid,
const guint8 *machine_id,
gsize machine_id_len)
{
@@ -3658,24 +3655,15 @@ nm_utils_dhcp_client_id_systemd_node_specific_full (gboolean legacy_unstable_byt
} duid;
} *client_id;
guint64 u64;
guint32 u32;
g_return_val_if_fail (interface_id, NULL);
g_return_val_if_fail (interface_id_len > 0, NULL);
g_return_val_if_fail (machine_id, NULL);
g_return_val_if_fail (machine_id_len > 0, NULL);
client_id = g_malloc (sizeof (*client_id));
client_id->type = 255;
u32 = nm_utils_create_dhcp_iaid (legacy_unstable_byteorder,
interface_id,
interface_id_len);
unaligned_write_be32 (&client_id->iaid, u32);
unaligned_write_be32 (&client_id->iaid, iaid);
unaligned_write_be16 (&client_id->duid.type, DUID_TYPE_EN);
unaligned_write_be32 (&client_id->duid.en.pen, SYSTEMD_PEN);
u64 = htole64 (c_siphash_hash (HASH_KEY, machine_id, machine_id_len));
@@ -3687,13 +3675,10 @@ nm_utils_dhcp_client_id_systemd_node_specific_full (gboolean legacy_unstable_byt
GBytes *
nm_utils_dhcp_client_id_systemd_node_specific (gboolean legacy_unstable_byteorder,
const char *ifname)
guint32 iaid)
{
g_return_val_if_fail (ifname && ifname[0], NULL);
return nm_utils_dhcp_client_id_systemd_node_specific_full (legacy_unstable_byteorder,
(const guint8 *) ifname,
strlen (ifname),
iaid,
(const guint8 *) nm_utils_machine_id_bin (),
sizeof (NMUuid));
}

View File

@@ -389,13 +389,12 @@ guint32 nm_utils_create_dhcp_iaid (gboolean legacy_unstable_byteorder,
gsize interface_id_len);
GBytes *nm_utils_dhcp_client_id_systemd_node_specific_full (gboolean legacy_unstable_byteorder,
const guint8 *interface_id,
gsize interface_id_len,
guint32 iaid,
const guint8 *machine_id,
gsize machine_id_len);
GBytes *nm_utils_dhcp_client_id_systemd_node_specific (gboolean legacy_unstable_byteorder,
const char *ifname);
guint32 iaid);
/*****************************************************************************/

View File

@@ -2084,10 +2084,11 @@ test_nm_utils_dhcp_client_id_systemd_node_specific (gconstpointer test_data)
gs_unref_bytes GBytes *client_id = NULL;
const guint8 *cid;
guint32 iaid = d->iaid_ifname;
guint32 tmp;
tmp = nm_utils_create_dhcp_iaid (TRUE, (const guint8 *) d->ifname, strlen (d->ifname));
client_id = nm_utils_dhcp_client_id_systemd_node_specific_full (legacy_unstable_byteorder,
(const guint8 *) d->ifname,
strlen (d->ifname),
tmp,
(const guint8 *) &d->machine_id,
sizeof (d->machine_id));