sd-dhcp-server: Add Hostname= option to static leases

This adds a new `Hostname=` option to the [DHCPServerStaticLease]
section in .network files, allowing an administrator to assign a
specific hostname to a client receiving a static lease.

We automatically select the correct DHCP option to use based on the
format of the provided string:

- Single DNS labels are sent as Option 12.
- Names with multiple DNS labels are sent as Option 81 in wire format.

Fixes: #39634
This commit is contained in:
Chris Down
2025-11-10 00:59:59 +08:00
committed by Yu Watanabe
parent c83f3f0837
commit 7f9c0c31d2
18 changed files with 409 additions and 36 deletions

View File

@@ -16,10 +16,12 @@ DNS=9.9.9.9
[DHCPServerStaticLease]
MACAddress=12:34:56:78:9a:bc
Address=10.1.1.2
Hostname=testhost
[DHCPServerStaticLease]
MACAddress=12:34:56:78:9a:bc
Address=10.1.1.3
Hostname=device.example.com
[DHCPServerStaticLease]
Address=10.1.1.4

View File

@@ -0,0 +1,11 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Name=veth99
[Network]
DHCP=ipv4
IPv6AcceptRA=no
[Link]
# This MAC overrides the default to match the second static lease
MACAddress=92:12:01:87:11:19

View File

@@ -0,0 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Name=veth99
[Network]
DHCP=ipv4
IPv6AcceptRA=no

View File

@@ -0,0 +1,27 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Name=veth-peer
[Network]
Address=10.1.1.1/24
DHCPServer=yes
IPv6AcceptRA=no
[DHCPServer]
PoolOffset=100
PoolSize=50
DefaultLeaseTimeSec=60
# Scenario 1: Option 12
# Matches veth99's default MAC (from 25-veth.netdev)
[DHCPServerStaticLease]
MACAddress=12:34:56:78:9a:bc
Address=10.1.1.200
Hostname=simple-host
# Scenario 2: Option 81
# Matches the MAC set by 25-dhcp-client-fqdn-hostname.network
[DHCPServerStaticLease]
MACAddress=92:12:01:87:11:19
Address=10.1.1.201
Hostname=fqdn.example.com

View File

@@ -7340,6 +7340,32 @@ class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
self.assertIn('Address: 10.1.1.200 (DHCPv4 via 10.1.1.1)', output)
self.assertRegex(output, 'DHCPv4 Client ID: IAID:[0-9a-z]*/DUID')
def test_dhcp_server_static_lease_hostname_simple(self):
copy_network_unit('25-veth.netdev',
'25-dhcp-client-simple-hostname.network',
'25-dhcp-server-static-hostname.network')
start_networkd()
self.wait_online('veth99:routable', 'veth-peer:routable')
output = networkctl_json('veth99')
check_json(output)
print(output)
data = json.loads(output)
self.assertEqual(data['DHCPv4Client']['Lease']['Hostname'], 'simple-host')
def test_dhcp_server_static_lease_hostname_fqdn(self):
copy_network_unit('25-veth.netdev',
'25-dhcp-client-fqdn-hostname.network',
'25-dhcp-server-static-hostname.network')
start_networkd()
self.wait_online('veth99:routable', 'veth-peer:routable')
output = networkctl_json('veth99')
check_json(output)
print(output)
data = json.loads(output)
self.assertEqual(data['DHCPv4Client']['Lease']['Hostname'], 'fqdn.example.com')
class NetworkdDHCPServerRelayAgentTests(unittest.TestCase, Utilities):
def setUp(self):