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