diff --git a/NEWS b/NEWS
index 62cc4698dc..1d1f08deda 100644
--- a/NEWS
+++ b/NEWS
@@ -78,6 +78,10 @@ CHANGES WITH 255 in spe:
simplified 2-message exchange instead of the typical 4-message
exchange if also supported by the DHCP server.
+ * The SendHostname and Hostname options are now available for the
+ DHCPv6 client, independent of the DHCPv4 option, so that these
+ configuration values can be set independently for each client.
+
Changes in systemd-analyze:
* "systemd-analyze plot" has gained tooltips on each unit name with
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 684a54e08b..4e360d7a8e 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -2829,6 +2829,30 @@ NFTSet=prefix:netdev:filter:eth_ipv4_prefix
+
+ SendHostname=
+
+ When true (the default), the machine's hostname (or the value specified with
+ Hostname=, described below) will be sent to the DHCPv6 server. Note that the
+ hostname must consist only of 7-bit ASCII lower-case characters and no spaces or dots, and be
+ formatted as a valid DNS domain name. Otherwise, the hostname is not sent even if this option
+ is true.
+
+
+
+
+
+
+ Hostname=
+
+ Use this value for the hostname which is sent to the DHCPv6 server, instead of machine's
+ hostname. Note that the specified hostname must consist only of 7-bit ASCII lower-case
+ characters and no spaces or dots, and be formatted as a valid DNS domain name.
+
+
+
+
+
diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c
index cfc7a388e8..195ce2d71f 100644
--- a/src/network/networkd-dhcp-common.c
+++ b/src/network/networkd-dhcp-common.c
@@ -481,6 +481,56 @@ int config_parse_ipv6_accept_ra_route_metric(
return 0;
}
+int config_parse_dhcp_send_hostname(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *network = userdata;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(IN_SET(ltype, AF_UNSPEC, AF_INET, AF_INET6));
+ assert(rvalue);
+ assert(data);
+
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse SendHostname=%s, ignoring assignment: %m", rvalue);
+ return 0;
+ }
+
+ switch (ltype) {
+ case AF_INET:
+ network->dhcp_send_hostname = r;
+ network->dhcp_send_hostname_set = true;
+ break;
+ case AF_INET6:
+ network->dhcp6_send_hostname = r;
+ network->dhcp6_send_hostname_set = true;
+ break;
+ case AF_UNSPEC:
+ /* For backward compatibility. */
+ if (!network->dhcp_send_hostname_set)
+ network->dhcp_send_hostname = r;
+ if (!network->dhcp6_send_hostname_set)
+ network->dhcp6_send_hostname = r;
+ break;
+ default:
+ assert_not_reached();
+ }
+
+ return 0;
+}
int config_parse_dhcp_use_dns(
const char* unit,
const char *filename,
diff --git a/src/network/networkd-dhcp-common.h b/src/network/networkd-dhcp-common.h
index ea942af721..6e3f3b2a1e 100644
--- a/src/network/networkd-dhcp-common.h
+++ b/src/network/networkd-dhcp-common.h
@@ -96,6 +96,7 @@ DHCPOptionDataType dhcp_option_data_type_from_string(const char *d) _pure_;
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_route_metric);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_route_metric);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_hostname);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_dns);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_domains);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_ntp);
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 0aa56bffbc..cc2c466cdd 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -522,10 +522,10 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
assert(link);
- if (!link->network->dhcp_send_hostname)
+ if (!link->network->dhcp6_send_hostname)
hn = NULL;
- else if (link->network->dhcp_hostname)
- hn = link->network->dhcp_hostname;
+ else if (link->network->dhcp6_hostname)
+ hn = link->network->dhcp6_hostname;
else {
r = gethostname_strict(&hostname);
if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index b87ae006f1..6323f6b212 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -230,7 +230,7 @@ DHCPv4.UseGateway, config_parse_tristate,
DHCPv4.QuickAck, config_parse_bool, 0, offsetof(Network, dhcp_quickack)
DHCPv4.RequestOptions, config_parse_dhcp_request_options, AF_INET, 0
DHCPv4.Anonymize, config_parse_bool, 0, offsetof(Network, dhcp_anonymize)
-DHCPv4.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname)
+DHCPv4.SendHostname, config_parse_dhcp_send_hostname, AF_INET, 0
DHCPv4.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname)
DHCPv4.Label, config_parse_dhcp_label, 0, offsetof(Network, dhcp_label)
DHCPv4.RequestBroadcast, config_parse_tristate, 0, offsetof(Network, dhcp_broadcast)
@@ -270,6 +270,8 @@ DHCPv6.UseDomains, config_parse_dhcp_use_domains,
DHCPv6.UseNTP, config_parse_dhcp_use_ntp, AF_INET6, 0
DHCPv6.UseCaptivePortal, config_parse_bool, 0, offsetof(Network, dhcp6_use_captive_portal)
DHCPv6.MUDURL, config_parse_mud_url, 0, offsetof(Network, dhcp6_mudurl)
+DHCPv6.SendHostname, config_parse_dhcp_send_hostname, AF_INET6, 0
+DHCPv6.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp6_hostname)
DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0
DHCPv6.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_user_class)
DHCPv6.VendorClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_vendor_class)
@@ -583,7 +585,7 @@ DHCP.UseDomains, config_parse_dhcp_use_domains,
DHCP.UseDomainName, config_parse_dhcp_use_domains, AF_UNSPEC, 0
DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_use_routes)
DHCP.Anonymize, config_parse_bool, 0, offsetof(Network, dhcp_anonymize)
-DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname)
+DHCP.SendHostname, config_parse_dhcp_send_hostname, AF_UNSPEC, 0
DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname)
DHCP.RequestBroadcast, config_parse_tristate, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 4a38bc88ae..b9119d9d18 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -410,6 +410,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.dhcp6_use_ntp = true,
.dhcp6_use_captive_portal = true,
.dhcp6_use_rapid_commit = true,
+ .dhcp6_send_hostname = true,
.dhcp6_duid.type = _DUID_TYPE_INVALID,
.dhcp6_client_start_mode = _DHCP6_CLIENT_START_MODE_INVALID,
.dhcp6_send_release = true,
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index e0891f9c18..00a6b50310 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -138,6 +138,7 @@ struct Network {
bool dhcp_socket_priority_set;
bool dhcp_anonymize;
bool dhcp_send_hostname;
+ bool dhcp_send_hostname_set;
int dhcp_broadcast;
int dhcp_ipv6_only_mode;
bool dhcp_use_rapid_commit;
@@ -173,6 +174,8 @@ struct Network {
/* DHCPv6 Client support */
bool dhcp6_use_address;
bool dhcp6_use_pd_prefix;
+ bool dhcp6_send_hostname;
+ bool dhcp6_send_hostname_set;
bool dhcp6_use_dns;
bool dhcp6_use_dns_set;
bool dhcp6_use_hostname;
@@ -188,6 +191,7 @@ struct Network {
DUID dhcp6_duid;
uint8_t dhcp6_pd_prefix_length;
struct in6_addr dhcp6_pd_prefix_hint;
+ char *dhcp6_hostname;
char *dhcp6_mudurl;
char **dhcp6_user_class;
char **dhcp6_vendor_class;