dhcp6: don't require a hardware address

The systemd DHCPv6 client requires a hardware address only to
determine the IAID; NM always overrides the IAID with its own and
therefore the hwaddr is not used.

Removing such requirement allows DHCPv6 to run over PPP, which is
useful with DHCPv6-PD to get a prefix from the ISP.

To test this, I set up a server with pppoe-server, radvd and the Wide
DHCPv6 server providing an address and a prefix. On the client, NM was
able to obtain a prefix using both dhcp=dhclient and dhcp=systemd.

Note that if there is no hardware address and you specify
ipv6.dhcp-duid=ll or ipv6.dhcp-iaid=mac, a warning will be emitted and
NM will use a random DUID/IAID.

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/478
This commit is contained in:
Beniamino Galvani 2020-07-09 14:29:41 +02:00
parent cfbaa2d8eb
commit 76a6a30577
4 changed files with 24 additions and 49 deletions

View file

@ -9616,7 +9616,6 @@ 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 *bcast_hwaddr = NULL;
gs_unref_bytes GBytes *duid = NULL;
gboolean enforce_duid = FALSE;
const NMPlatformLink *pllink;
@ -9646,20 +9645,16 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
}
pllink = nm_platform_link_get (nm_device_get_platform (self), nm_device_get_ip_ifindex (self));
if (pllink) {
if (pllink)
hwaddr = nmp_link_address_get_as_bytes (&pllink->l_address);
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->dhcp_data_6.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),
hwaddr,
bcast_hwaddr,
&ll_addr->address,
nm_connection_get_uuid (connection),
nm_device_get_route_table (self, AF_INET6),

View file

@ -240,21 +240,27 @@ client_start (NMDhcpManager *self,
g_return_val_if_fail (!dhcp_client_id || g_bytes_get_size (dhcp_client_id) >= 2, NULL);
g_return_val_if_fail (!error || !*error, NULL);
if (!hwaddr || !bcast_hwaddr) {
nm_utils_error_set (error,
NM_UTILS_ERROR_UNKNOWN,
"missing %s address",
hwaddr ? "broadcast" : "MAC");
return NULL;
}
if (addr_family == AF_INET) {
if (!hwaddr || !bcast_hwaddr) {
nm_utils_error_set (error,
NM_UTILS_ERROR_UNKNOWN,
"missing %s address",
hwaddr ? "broadcast" : "MAC");
return NULL;
}
hwaddr_len = g_bytes_get_size (hwaddr);
if ( hwaddr_len == 0
|| hwaddr_len > NM_UTILS_HWADDR_LEN_MAX) {
nm_utils_error_set (error,
NM_UTILS_ERROR_UNKNOWN,
"invalid MAC address");
g_return_val_if_reached (NULL) ;
hwaddr_len = g_bytes_get_size (hwaddr);
if ( hwaddr_len == 0
|| hwaddr_len > NM_UTILS_HWADDR_LEN_MAX) {
nm_utils_error_set (error,
NM_UTILS_ERROR_UNKNOWN,
"invalid MAC address");
g_return_val_if_reached (NULL) ;
}
nm_assert (g_bytes_get_size (hwaddr) == g_bytes_get_size (bcast_hwaddr));
} else {
hwaddr = NULL;
bcast_hwaddr = NULL;
}
if (hostname) {
@ -268,8 +274,6 @@ client_start (NMDhcpManager *self,
}
}
nm_assert (g_bytes_get_size (hwaddr) == g_bytes_get_size (bcast_hwaddr));
priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
/* Kill any old client instance */
@ -457,8 +461,6 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
GBytes *hwaddr,
GBytes *bcast_hwaddr,
const struct in6_addr *ll_addr,
const char *uuid,
guint32 route_table,
@ -493,8 +495,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
multi_idx,
iface,
ifindex,
hwaddr,
bcast_hwaddr,
NULL,
NULL,
uuid,
route_table,
route_metric,

View file

@ -54,8 +54,6 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager,
struct _NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
GBytes *hwaddr,
GBytes *bcast_hwaddr,
const struct in6_addr *ll_addr,
const char *uuid,
guint32 route_table,

View file

@ -903,16 +903,12 @@ ip6_start (NMDhcpClient *client,
NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client);
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
nm_auto (sd_dhcp6_client_unrefp) sd_dhcp6_client *sd_client = NULL;
GBytes *hwaddr;
const char *hostname;
const char *mud_url;
int r, i;
const guint8 *duid_arr;
gsize duid_len;
GBytes *duid;
const uint8_t *hwaddr_arr;
gsize hwaddr_len;
int arp_type;
g_return_val_if_fail (!priv->client4, FALSE);
g_return_val_if_fail (!priv->client6, FALSE);
@ -957,22 +953,6 @@ ip6_start (NMDhcpClient *client,
return FALSE;
}
hwaddr = nm_dhcp_client_get_hw_addr (client);
if ( !hwaddr
|| !(hwaddr_arr = g_bytes_get_data (hwaddr, &hwaddr_len))
|| (arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len)) < 0) {
nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address");
return FALSE;
}
r = sd_dhcp6_client_set_mac (sd_client,
hwaddr_arr,
hwaddr_len,
(guint16) arp_type);
if (r < 0) {
nm_utils_error_set_errno (error, r, "failed to set MAC address: %s");
return FALSE;
}
r = sd_dhcp6_client_set_ifindex (sd_client,
nm_dhcp_client_get_ifindex (client));
if (r < 0) {