network: renew DHCPv6 lease when system hostname changes

Previously, the new hostname was sent to the DHCPv6 server only on the
next renewal. Now, the lease is renewed immediately, as is done for
DHCPv4. As with DHCPv4, this is skipped when the new hostname is the
one provided in the current lease, as the server already knows it.

Unlike DHCPv4, the hostname is set from the DHCPv6 lease on every
reply, including the ones for renewals. Hence, when the hostname is
set from the lease of this link, the renewal is also skipped if the
hostname was set from the lease of another link, otherwise two links
whose servers provide different hostnames would renew their leases
endlessly.

Also, skip updating the hostname when SendHostname=no, to avoid a
pointless renewal.
This commit is contained in:
khromenokroman authored and Yu Watanabe committed 2026-10-21 16:48:33 +09:00
1 parent 543ef9fc10
commit a28fbedfe2
3 files changed
+59 -14

No files matched your search

+6 -6
View File
@@ -48,12 +48,12 @@ CHANGES WITH 263 in spe:
* systemd-networkd now updates the hostname sent by the DHCPv4 and
DHCPv6 clients when the system hostname is changed. Previously, the
hostname known when the interface was configured was sent until the
interface was reconfigured. The DHCPv4 lease is renewed immediately
to send the new hostname, while for DHCPv6 the new hostname is sent
on the next renewal. Since some DHCP servers provide different
settings depending on the hostname sent by the client, the previous
behaviour may be restored with the new SendHostnameUpdates=no
setting in the [DHCPv4] and [DHCPv6] sections.
interface was reconfigured. The DHCPv4 and DHCPv6 leases are renewed
immediately to send the new hostname. Since some DHCP servers
provide different settings depending on the hostname sent by the
client, the previous behaviour may be restored with the new
SendHostnameUpdates=no setting in the [DHCPv4] and [DHCPv6]
sections.
* The "appStream" key of
org.freedesktop.sysupdate1.Target.DescribeFeature() is now an array of
+2 -4
View File
@@ -3288,10 +3288,8 @@ MultiPathRoute=2001:db8::1@eth0</programlisting>
<varlistentry>
<term><varname>SendHostnameUpdates=</varname></term>
<listitem>
<para>As in the [DHCPv4] section, but for the DHCPv6 client. Note that the lease is not renewed
immediately, the new hostname is sent to the DHCPv6 server on the next renewal. This setting has
no effect when <varname>SendHostname=no</varname> or <varname>Hostname=</varname> is
specified.</para>
<para>As in the [DHCPv4] section, but for the DHCPv6 client. This setting has no effect when
<varname>SendHostname=no</varname> or <varname>Hostname=</varname> is specified.</para>
<xi:include href="version-info.xml" xpointer="v263"/>
</listitem>
+51 -4
View File
@@ -817,18 +817,65 @@ int dhcp6_update_mac(Link *link) {
return 0;
}
static bool dhcp6_hostname_is_from_lease(Link *link) {
_cleanup_free_ char *hostname = NULL;
const char *dhcpname;
assert(link);
assert(link->manager);
if (!link->dhcp6_lease)
return false;
if (sd_dhcp6_lease_get_fqdn(link->dhcp6_lease, &dhcpname) < 0)
return false;
/* An overlong hostname in the lease is shortened when it is set as the system hostname. */
if (shorten_overlong(dhcpname, &hostname) < 0)
return false;
return streq_ptr(link->manager->kernel_hostname, hostname);
}
int dhcp6_update_hostname(Link *link) {
int r;
assert(link);
if (!link->dhcp6_client || !link->network)
return 0;
/* An explicitly configured hostname does not follow the system hostname. */
if (!link->network->dhcp6_send_hostname_updates || link->network->dhcp6_hostname)
/* No hostname is sent when disabled, and an explicitly configured one does not follow the system
* hostname. */
if (!link->network->dhcp6_send_hostname ||
!link->network->dhcp6_send_hostname_updates ||
link->network->dhcp6_hostname)
return 0;
/* The new hostname will be sent on the next renewal. */
return dhcp6_set_hostname(link->dhcp6_client, link);
r = dhcp6_set_hostname(link->dhcp6_client, link);
if (r < 0)
return r;
/* If the hostname was set from the current lease, the server already knows it. The new hostname
* will be sent on the next renewal. */
if (dhcp6_hostname_is_from_lease(link))
return 0;
/* Unlike DHCPv4, the hostname is set from the lease on every reply, including the ones for
* renewals. Hence, if the hostname was set from the lease of another link, renewing the lease
* here may make the server of this link provide another hostname, which then makes the other
* link renew its lease, and so on. */
if (link->network->dhcp6_use_hostname &&
streq_ptr(link->manager->kernel_hostname, link->manager->dynamic_hostname))
return 0;
/* Send the new hostname to the server now, rather than on the next renewal. If no lease is
* acquired yet, this does nothing, and the new hostname will be sent in the next message anyway. */
r = sd_dhcp6_client_send_renew(link->dhcp6_client);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to renew lease after hostname change: %m");
return 0;
}
static int dhcp6_process_request(Request *req, Link *link, void *userdata) {