diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml
index 3b592e9a67..f751b20104 100644
--- a/man/networkd.conf.xml
+++ b/man/networkd.conf.xml
@@ -256,6 +256,17 @@ DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00
+
+
+ UseDomains=
+ Specifies the default value for per-network UseDomains=.
+ Takes a boolean. See for details in
+ systemd.network5.
+ Defaults to no.
+
+
+
+
@@ -280,6 +291,13 @@ DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00
+
+
+ UseDomains=
+ As in the [DHCPv4] section.
+
+
+
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 3c887b0105..38ab30fb4d 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -2570,7 +2570,9 @@ NFTSet=prefix:netdev:filter:eth_ipv4_prefix
effect of the setting. If set to , the domain name
received from the DHCP server will be used for routing DNS queries only, but not for searching,
similarly to the effect of the setting when the argument is prefixed with
- ~. Defaults to false.
+ ~. When unspecified, the value specified in the same setting in
+ networkd.conf5,
+ which defaults to no, will be used.
It is recommended to enable this option only on trusted networks, as setting this
affects resolution of all hostnames, in particular of single-label names. It is generally
diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c
index 2b442aa4c1..3015e2b5c8 100644
--- a/src/network/networkd-dhcp-common.c
+++ b/src/network/networkd-dhcp-common.c
@@ -632,6 +632,8 @@ int config_parse_dhcp_use_domains(
return 0;
}
+DEFINE_CONFIG_PARSE_ENUM(config_parse_default_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse UseDomains=")
+
int config_parse_dhcp_use_ntp(
const char* unit,
const char *filename,
diff --git a/src/network/networkd-dhcp-common.h b/src/network/networkd-dhcp-common.h
index c3e6a6d51c..53e3e12f53 100644
--- a/src/network/networkd-dhcp-common.h
+++ b/src/network/networkd-dhcp-common.h
@@ -99,6 +99,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_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_default_dhcp_use_domains);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_ntp);
CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_or_ra_route_table);
diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf
index f443fa3ece..0c23b4ba82 100644
--- a/src/network/networkd-gperf.gperf
+++ b/src/network/networkd-gperf.gperf
@@ -30,8 +30,10 @@ Network.RouteTable, config_parse_route_table_names,
Network.IPv4Forwarding, config_parse_tristate, 0, offsetof(Manager, ip_forwarding[0])
Network.IPv6Forwarding, config_parse_tristate, 0, offsetof(Manager, ip_forwarding[1])
Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Manager, ipv6_privacy_extensions)
+DHCPv4.UseDomains, config_parse_default_dhcp_use_domains, 0, offsetof(Manager, dhcp_use_domains)
DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp_duid)
DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, dhcp_duid)
+DHCPv6.UseDomains, config_parse_default_dhcp_use_domains, 0, offsetof(Manager, dhcp6_use_domains)
DHCPv6.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp6_duid)
DHCPv6.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, dhcp6_duid)
DHCPServer.PersistLeases, config_parse_bool, 0, offsetof(Manager, dhcp_server_persist_leases)
diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h
index 28a2803845..9f621b7486 100644
--- a/src/network/networkd-manager.h
+++ b/src/network/networkd-manager.h
@@ -64,6 +64,9 @@ struct Manager {
OrderedSet *address_pools;
Set *dhcp_pd_subnet_ids;
+ DHCPUseDomains dhcp_use_domains;
+ DHCPUseDomains dhcp6_use_domains;
+
DUID dhcp_duid;
DUID dhcp6_duid;
DUID duid_product_uuid;
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index d42ded6160..833f1bd059 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -388,6 +388,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.dhcp_use_captive_portal = true,
.dhcp_use_dns = true,
.dhcp_routes_to_dns = true,
+ .dhcp_use_domains = manager->dhcp_use_domains,
.dhcp_use_hostname = true,
.dhcp_use_routes = true,
.dhcp_use_gateway = -1,
@@ -404,6 +405,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.dhcp6_use_address = true,
.dhcp6_use_pd_prefix = true,
.dhcp6_use_dns = true,
+ .dhcp6_use_domains = manager->dhcp6_use_domains,
.dhcp6_use_hostname = true,
.dhcp6_use_ntp = true,
.dhcp6_use_captive_portal = true,
diff --git a/src/network/networkd.conf b/src/network/networkd.conf
index bad7e8855a..828dbb9638 100644
--- a/src/network/networkd.conf
+++ b/src/network/networkd.conf
@@ -28,10 +28,12 @@
[DHCPv4]
#DUIDType=vendor
#DUIDRawData=
+#UseDomains=no
[DHCPv6]
#DUIDType=vendor
#DUIDRawData=
+#UseDomains=no
[DHCPServer]
#PersistLeases=yes
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 4c69bc9033..86a0ff12b4 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -6839,6 +6839,50 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
check(self, True, False)
check(self, False, True)
check(self, False, False)
+
+ def test_dhcp_client_default_use_domains(self):
+ def check(self, ipv4, ipv6):
+ mkdir_p(networkd_conf_dropin_dir)
+ with open(os.path.join(networkd_conf_dropin_dir, 'default_use_domains.conf'), mode='w', encoding='utf-8') as f:
+ f.write('[DHCPv4]\nUseDomains=')
+ f.write('yes\n' if ipv4 else 'no\n')
+ f.write('[DHCPv6]\nUseDomains=')
+ f.write('yes\n' if ipv6 else 'no\n')
+
+ restart_networkd()
+ self.wait_online('veth-peer:carrier')
+ start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1',
+ '--dhcp-option=option6:dns-server,[2600::1]',
+ '--dhcp-option=option:domain-search,example.com',
+ '--dhcp-option=option6:domain-search,example.com')
+
+ self.wait_online('veth99:routable')
+
+ # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
+ self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
+ self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
+
+ for _ in range(20):
+ output = resolvectl('domain', 'veth99')
+ if ipv4 or ipv6:
+ if 'example.com' in output:
+ break
+ else:
+ if 'example.com' not in output:
+ break
+ time.sleep(0.5)
+ else:
+ print(output)
+ self.fail('unexpected domain setting in resolved...')
+
+ stop_dnsmasq()
+ remove_networkd_conf_dropin('default_use_domains.conf')
+
+ copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
+ check(self, True, True)
+ check(self, True, False)
+ check(self, False, True)
+ check(self, False, False)
def test_dhcp_client_use_captive_portal(self):
def check(self, ipv4, ipv6):