From daffee2cbf001dab13799f5b2b69330162491214 Mon Sep 17 00:00:00 2001
From: sarthurdev <965089+sarthurdev@users.noreply.github.com>
Date: Sun, 7 Jan 2024 09:24:10 +0100
Subject: dhcp: T3316: Move options to separate node and extend scopes
---
interface-definitions/include/dhcp/option-v4.xml.i | 257 +++++++++++++++++++++
.../include/version/dhcp-server-version.xml.i | 2 +-
2 files changed, 258 insertions(+), 1 deletion(-)
create mode 100644 interface-definitions/include/dhcp/option-v4.xml.i
(limited to 'interface-definitions/include')
diff --git a/interface-definitions/include/dhcp/option-v4.xml.i b/interface-definitions/include/dhcp/option-v4.xml.i
new file mode 100644
index 000000000..bd6fc6043
--- /dev/null
+++ b/interface-definitions/include/dhcp/option-v4.xml.i
@@ -0,0 +1,257 @@
+
+
+
+ DHCP option
+
+
+ #include
+ #include
+ #include
+ #include
+ #include
+
+
+ Bootstrap file name
+
+ [[:ascii:]]{1,253}
+
+
+
+
+
+ Server from which the initial boot file is to be loaded
+
+ ipv4
+ Bootfile server IPv4 address
+
+
+ hostname
+ Bootfile server FQDN
+
+
+
+
+
+
+
+
+
+ Bootstrap file size
+
+ u32:1-16
+ Bootstrap file size in 512 byte blocks
+
+
+
+
+
+
+
+
+ Specifies the clients subnet mask as per RFC 950. If unset, subnet declaration is used.
+
+ u32:0-32
+ DHCP client prefix length must be 0 to 32
+
+
+
+
+ DHCP client prefix length must be 0 to 32
+
+
+
+
+ IP address of default router
+
+ ipv4
+ Default router IPv4 address
+
+
+
+
+
+
+
+
+ Enable IP forwarding on client
+
+
+
+
+
+ Disable IPv4 on IPv6 only hosts (RFC 8925)
+
+ u32
+ Seconds
+
+
+
+
+ Seconds must be between 0 and 4294967295 (49 days)
+
+
+
+
+ IP address of POP3 server
+
+ ipv4
+ POP3 server IPv4 address
+
+
+
+
+
+
+
+
+
+ Address for DHCP server identifier
+
+ ipv4
+ DHCP server identifier IPv4 address
+
+
+
+
+
+
+
+
+ IP address of SMTP server
+
+ ipv4
+ SMTP server IPv4 address
+
+
+
+
+
+
+
+
+
+ Classless static route destination subnet
+
+ ipv4net
+ IPv4 address and prefix length
+
+
+
+
+
+
+
+
+ IP address of router to be used to reach the destination subnet
+
+ ipv4
+ IPv4 address of router
+
+
+
+
+
+
+
+
+
+
+ TFTP server name
+
+ ipv4
+ TFTP server IPv4 address
+
+
+ hostname
+ TFTP server FQDN
+
+
+
+
+
+
+
+
+
+ Client subnet offset in seconds from Coordinated Universal Time (UTC)
+
+ [-]N
+ Time offset (number, may be negative)
+
+
+ -?[0-9]+
+
+ Invalid time offset value
+
+
+
+
+ IP address of time server
+
+ ipv4
+ Time server IPv4 address
+
+
+
+
+
+
+
+
+
+ Time zone to send to clients. Uses RFC4833 options 100 and 101
+
+
+
+
+
+
+
+
+
+
+ Vendor Specific Options
+
+
+
+
+ Ubiquiti specific parameters
+
+
+
+
+ Address of UniFi controller
+
+ ipv4
+ IP address of UniFi controller
+
+
+
+
+
+
+
+
+
+
+
+
+ IP address for Windows Internet Name Service (WINS) server
+
+ ipv4
+ WINS server IPv4 address
+
+
+
+
+
+
+
+
+
+ Web Proxy Autodiscovery (WPAD) URL
+
+
+
+
+
diff --git a/interface-definitions/include/version/dhcp-server-version.xml.i b/interface-definitions/include/version/dhcp-server-version.xml.i
index cc84ea8b9..d83172e72 100644
--- a/interface-definitions/include/version/dhcp-server-version.xml.i
+++ b/interface-definitions/include/version/dhcp-server-version.xml.i
@@ -1,3 +1,3 @@
-
+
--
cgit v1.2.3
From 74ddb29c6c9ce31450234e77fd39c73d0d51c3c5 Mon Sep 17 00:00:00 2001
From: sarthurdev <965089+sarthurdev@users.noreply.github.com>
Date: Sun, 7 Jan 2024 21:41:23 +0100
Subject: dhcp: T3316: Fix `listen-address` handling and add `listen-interface`
as supported by Kea
---
data/templates/dhcp-server/kea-dhcp4.conf.j2 | 8 ++++++++
.../include/listen-interface-multi-broadcast.xml.i | 18 ++++++++++++++++++
interface-definitions/service_dhcp-server.xml.in | 1 +
python/vyos/template.py | 17 +++++++++++++++++
python/vyos/utils/network.py | 4 ++--
smoketest/scripts/cli/test_service_dhcp-server.py | 9 +++++++--
src/conf_mode/service_dhcp-server.py | 9 ++++++++-
7 files changed, 61 insertions(+), 5 deletions(-)
create mode 100644 interface-definitions/include/listen-interface-multi-broadcast.xml.i
(limited to 'interface-definitions/include')
diff --git a/data/templates/dhcp-server/kea-dhcp4.conf.j2 b/data/templates/dhcp-server/kea-dhcp4.conf.j2
index 6ab13ab27..629fa952a 100644
--- a/data/templates/dhcp-server/kea-dhcp4.conf.j2
+++ b/data/templates/dhcp-server/kea-dhcp4.conf.j2
@@ -1,8 +1,16 @@
{
"Dhcp4": {
"interfaces-config": {
+{% if listen_address is vyos_defined %}
+ "interfaces": {{ listen_address | kea_address_json }},
+ "dhcp-socket-type": "udp",
+{% elif listen_interface is vyos_defined %}
+ "interfaces": {{ listen_interface | tojson }},
+ "dhcp-socket-type": "raw",
+{% else %}
"interfaces": [ "*" ],
"dhcp-socket-type": "raw",
+{% endif %}
"service-sockets-max-retries": 5,
"service-sockets-retry-wait-time": 5000
},
diff --git a/interface-definitions/include/listen-interface-multi-broadcast.xml.i b/interface-definitions/include/listen-interface-multi-broadcast.xml.i
new file mode 100644
index 000000000..b3d5a3ecc
--- /dev/null
+++ b/interface-definitions/include/listen-interface-multi-broadcast.xml.i
@@ -0,0 +1,18 @@
+
+
+
+ Interface for DHCP Relay Agent to listen for requests
+
+
+
+
+ txt
+ Interface name
+
+
+ #include
+
+
+
+
+
diff --git a/interface-definitions/service_dhcp-server.xml.in b/interface-definitions/service_dhcp-server.xml.in
index a5cee62d1..27485b6d4 100644
--- a/interface-definitions/service_dhcp-server.xml.in
+++ b/interface-definitions/service_dhcp-server.xml.in
@@ -74,6 +74,7 @@
#include
+ #include
Name of DHCP shared network
diff --git a/python/vyos/template.py b/python/vyos/template.py
index c0c09f690..1368f1f61 100644
--- a/python/vyos/template.py
+++ b/python/vyos/template.py
@@ -786,6 +786,23 @@ def range_to_regex(num_range):
regex = range_to_regex(num_range)
return f'({regex})'
+@register_filter('kea_address_json')
+def kea_address_json(addresses):
+ from json import dumps
+ from vyos.utils.network import is_addr_assigned
+
+ out = []
+
+ for address in addresses:
+ ifname = is_addr_assigned(address, return_ifname=True)
+
+ if not ifname:
+ continue
+
+ out.append(f'{ifname}/{address}')
+
+ return dumps(out)
+
@register_filter('kea_failover_json')
def kea_failover_json(config):
from json import dumps
diff --git a/python/vyos/utils/network.py b/python/vyos/utils/network.py
index 997ee6309..b782e0bd8 100644
--- a/python/vyos/utils/network.py
+++ b/python/vyos/utils/network.py
@@ -308,7 +308,7 @@ def is_ipv6_link_local(addr):
return False
-def is_addr_assigned(ip_address, vrf=None) -> bool:
+def is_addr_assigned(ip_address, vrf=None, return_ifname=False) -> bool | str:
""" Verify if the given IPv4/IPv6 address is assigned to any interface """
from netifaces import interfaces
from vyos.utils.network import get_interface_config
@@ -323,7 +323,7 @@ def is_addr_assigned(ip_address, vrf=None) -> bool:
continue
if is_intf_addr_assigned(interface, ip_address):
- return True
+ return interface if return_ifname else True
return False
diff --git a/smoketest/scripts/cli/test_service_dhcp-server.py b/smoketest/scripts/cli/test_service_dhcp-server.py
index 99ac406cd..ef6191fb1 100755
--- a/smoketest/scripts/cli/test_service_dhcp-server.py
+++ b/smoketest/scripts/cli/test_service_dhcp-server.py
@@ -32,6 +32,7 @@ CTRL_PROCESS_NAME = 'kea-ctrl-agent'
KEA4_CONF = '/run/kea/kea-dhcp4.conf'
KEA4_CTRL = '/run/kea/dhcp4-ctrl-socket'
base_path = ['service', 'dhcp-server']
+interface = 'dum8765'
subnet = '192.0.2.0/25'
router = inc_ip(subnet, 1)
dns_1 = inc_ip(subnet, 2)
@@ -46,11 +47,11 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
cls.cli_delete(cls, base_path)
cidr_mask = subnet.split('/')[-1]
- cls.cli_set(cls, ['interfaces', 'dummy', 'dum8765', 'address', f'{router}/{cidr_mask}'])
+ cls.cli_set(cls, ['interfaces', 'dummy', interface, 'address', f'{router}/{cidr_mask}'])
@classmethod
def tearDownClass(cls):
- cls.cli_delete(cls, ['interfaces', 'dummy', 'dum8765'])
+ cls.cli_delete(cls, ['interfaces', 'dummy', interface])
super(TestServiceDHCPServer, cls).tearDownClass()
def tearDown(self):
@@ -95,6 +96,8 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
range_1_start = inc_ip(subnet, 40)
range_1_stop = inc_ip(subnet, 50)
+ self.cli_set(base_path + ['listen-interface', interface])
+
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
# we use the first subnet IP address as default gateway
self.cli_set(pool + ['option', 'default-router', router])
@@ -116,6 +119,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
config = read_file(KEA4_CONF)
obj = loads(config)
+ self.verify_config_value(obj, ['Dhcp4', 'interfaces-config'], 'interfaces', [interface])
self.verify_config_value(obj, ['Dhcp4', 'shared-networks'], 'name', shared_net_name)
self.verify_config_value(obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'subnet', subnet)
self.verify_config_value(obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'valid-lifetime', 86400)
@@ -607,6 +611,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
config = read_file(KEA4_CONF)
obj = loads(config)
+ self.verify_config_value(obj, ['Dhcp4', 'interfaces-config'], 'interfaces', [f'{interface}/{router}'])
self.verify_config_value(obj, ['Dhcp4', 'shared-networks'], 'name', 'RELAY')
self.verify_config_value(obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'subnet', relay_subnet)
diff --git a/src/conf_mode/service_dhcp-server.py b/src/conf_mode/service_dhcp-server.py
index 7ebc560ba..329e18993 100755
--- a/src/conf_mode/service_dhcp-server.py
+++ b/src/conf_mode/service_dhcp-server.py
@@ -31,6 +31,7 @@ from vyos.utils.file import chmod_775
from vyos.utils.file import makedir
from vyos.utils.file import write_file
from vyos.utils.process import call
+from vyos.utils.network import interface_exists
from vyos.utils.network import is_subnet_connected
from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
@@ -294,12 +295,18 @@ def verify(dhcp):
else:
raise ConfigError(f'listen-address "{address}" not configured on any interface')
-
if not listen_ok:
raise ConfigError('None of the configured subnets have an appropriate primary IP address on any\n'
'broadcast interface configured, nor was there an explicit listen-address\n'
'configured for serving DHCP relay packets!')
+ if 'listen_address' in dhcp and 'listen_interface' in dhcp:
+ raise ConfigError(f'Cannot define listen-address and listen-interface at the same time')
+
+ for interface in (dict_search('listen_interface', dhcp) or []):
+ if not interface_exists(interface):
+ raise ConfigError(f'listen-interface "{interface}" does not exist')
+
return None
def generate(dhcp):
--
cgit v1.2.3