network: add DHCP server domain name option support (#39260)

Implements DHCP option 15 (Domain Name) for systemd-networkd's DHCP
server, allowing administrators to configure the DNS default domain that
clients should use.

This addresses the feature request in issue #37077, where users needed
to manually configure domain names using
SendOption=15:string:example.com as a workaround.

This adds two new configuration options to the [DHCPServer] section:
- EmitDomain= (boolean): whether to send domain name to clients
- Domain= (string): the domain name to send (e.g., "example.com")

Example configuration:
  [DHCPServer] EmitDomain=yes Domain=example.com

This eliminates the need for manual workarounds using
SendOption=15:string:...

Fixes #37077
This commit is contained in:
Govind Venugopal
2025-10-15 11:20:41 +02:00
committed by GitHub
parent 4cae0e9a78
commit 3eb7b881bd
9 changed files with 148 additions and 0 deletions
+48
View File
@@ -13,6 +13,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "hashmap.h"
#include "hostname-setup.h"
#include "network-common.h"
#include "networkd-address.h"
#include "networkd-dhcp-server.h"
@@ -31,6 +32,30 @@
#include "string-util.h"
#include "strv.h"
static int get_hostname_domain(char **ret) {
_cleanup_free_ char *hostname = NULL;
const char *domain;
int r;
assert(ret);
/* Get the full hostname (FQDN if available) */
r = gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST | GET_HOSTNAME_FALLBACK_DEFAULT, &hostname);
if (r < 0)
return r;
/* Find the first dot to extract the domain part */
domain = strchr(hostname, '.');
if (!domain)
return -ENOENT; /* No domain part in hostname */
domain++; /* Skip the dot */
if (isempty(domain))
return -ENOENT; /* Empty domain after dot */
return strdup_to(ret, domain);
}
static bool link_dhcp4_server_enabled(Link *link) {
assert(link);
@@ -678,6 +703,29 @@ static int dhcp4_server_configure(Link *link) {
}
}
if (link->network->dhcp_server_emit_domain) {
_cleanup_free_ char *buffer = NULL;
const char *domain = NULL;
if (link->network->dhcp_server_domain)
domain = link->network->dhcp_server_domain;
else {
r = get_hostname_domain(&buffer);
if (r < 0)
log_link_warning_errno(link, r, "Failed to determine domain name from host's hostname, will not send domain in DHCP leases: %m");
else {
domain = buffer;
log_link_debug(link, "Using autodetected domain name '%s' for DHCP server.", domain);
}
}
if (domain) {
r = sd_dhcp_server_set_domain_name(link->dhcp_server, domain);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set domain name for DHCP server: %m");
}
}
ORDERED_HASHMAP_FOREACH(p, link->network->dhcp_server_send_options) {
r = sd_dhcp_server_add_option(link->dhcp_server, p);
if (r == -EEXIST)
+2
View File
@@ -381,6 +381,8 @@ DHCPServer.EmitRouter, config_parse_bool,
DHCPServer.Router, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_server_router)
DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone)
DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone)
DHCPServer.EmitDomain, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_domain)
DHCPServer.Domain, config_parse_dns_name, 0, offsetof(Network, dhcp_server_domain)
DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset)
DHCPServer.PoolSize, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_size)
DHCPServer.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_server_send_vendor_options)
+1
View File
@@ -755,6 +755,7 @@ static Network *network_free(Network *network) {
free(network->dhcp_server_boot_server_name);
free(network->dhcp_server_boot_filename);
free(network->dhcp_server_timezone);
free(network->dhcp_server_domain);
free(network->dhcp_server_uplink_name);
for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
free(network->dhcp_server_emit[t].addresses);
+2
View File
@@ -220,6 +220,8 @@ typedef struct Network {
struct in_addr dhcp_server_router;
bool dhcp_server_emit_timezone;
char *dhcp_server_timezone;
bool dhcp_server_emit_domain;
char *dhcp_server_domain;
usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec;
uint32_t dhcp_server_pool_offset;
uint32_t dhcp_server_pool_size;