diff options
author | Christian Poessinger <christian@poessinger.com> | 2020-12-07 06:18:11 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-07 06:18:11 +0100 |
commit | 722e886ac2bf644dd904f0a5049f6bcac7951ccb (patch) | |
tree | bb20e202d09c8ee0d9b58244c214d28b9e973c7a | |
parent | 6b7aa5ae54b52875b82a42b41ffea939d2eba180 (diff) | |
parent | eecec6b5caeaef14a03ddbb1d09f9c599273b998 (diff) | |
download | vyos-1x-722e886ac2bf644dd904f0a5049f6bcac7951ccb.tar.gz vyos-1x-722e886ac2bf644dd904f0a5049f6bcac7951ccb.zip |
Merge pull request #636 from c-po/t2562-dhcp
dhcp: T2562: add "listen-address" CLI node for better DHCP relay support
-rw-r--r-- | data/templates/dhcp-server/dhcpd.conf.tmpl | 8 | ||||
-rw-r--r-- | interface-definitions/dhcp-server.xml.in | 11 | ||||
-rw-r--r-- | python/vyos/template.py | 41 | ||||
-rwxr-xr-x | src/conf_mode/dhcp_server.py | 16 |
4 files changed, 64 insertions, 12 deletions
diff --git a/data/templates/dhcp-server/dhcpd.conf.tmpl b/data/templates/dhcp-server/dhcpd.conf.tmpl index bcf425abd..56a5f4bcd 100644 --- a/data/templates/dhcp-server/dhcpd.conf.tmpl +++ b/data/templates/dhcp-server/dhcpd.conf.tmpl @@ -62,6 +62,14 @@ failover peer "{{ subnet_config.failover.name }}" { {% endif %} {% endfor %} {% endif %} +{% if listen_address is defined and listen_address is not none %} + +# DHCP server serving relay subnet, we need a connector to the real world +{% for address in listen_address %} +# Connected subnet statement for listen-address {{ address }} +subnet {{ address | network_from_ipv4 }} netmask {{ address | netmask_from_ipv4 }} { } +{% endfor %} +{% endif %} # Shared network configration(s) {% if shared_network_name is defined and shared_network_name is not none %} diff --git a/interface-definitions/dhcp-server.xml.in b/interface-definitions/dhcp-server.xml.in index 2f78f11ea..161eeed28 100644 --- a/interface-definitions/dhcp-server.xml.in +++ b/interface-definitions/dhcp-server.xml.in @@ -11,13 +11,13 @@ <children> <leafNode name="disable"> <properties> - <help>Option to disable DHCP server</help> + <help>Disable DHCP server</help> <valueless/> </properties> </leafNode> <leafNode name="dynamic-dns-update"> <properties> - <help>DHCP server to dynamically update the Domain Name System (DNS)</help> + <help>Dynamically update Domain Name System (RFC4702)</help> <valueless/> </properties> </leafNode> @@ -32,19 +32,20 @@ </leafNode> <leafNode name="hostfile-update"> <properties> - <help>Enable DHCP server updating /etc/hosts (per client lease)</help> + <help>Updating /etc/hosts file (per client lease)</help> <valueless/> </properties> </leafNode> <leafNode name="host-decl-name"> <properties> - <help>Instruct server to use host declaration name for forward DNS name</help> + <help>Use host declaration name for forward DNS name</help> <valueless/> </properties> </leafNode> + #include <include/listen-address.xml.i> <tagNode name="shared-network-name"> <properties> - <help>DHCP shared network name [REQUIRED]</help> + <help>Name of DHCP shared network</help> <constraint> <regex>[-_a-zA-Z0-9.]+</regex> </constraint> diff --git a/python/vyos/template.py b/python/vyos/template.py index 5993ffd95..63d400642 100644 --- a/python/vyos/template.py +++ b/python/vyos/template.py @@ -123,23 +123,56 @@ def render( ################################## @register_filter('address_from_cidr') -def address_from_cidr(text): +def address_from_cidr(prefix): """ Take an IPv4/IPv6 CIDR prefix and convert the network to an "address". Example: 192.0.2.0/24 -> 192.0.2.0, 2001:db8::/48 -> 2001:db8:: """ from ipaddress import ip_network - return str(ip_network(text).network_address) + return str(ip_network(prefix).network_address) @register_filter('netmask_from_cidr') -def netmask_from_cidr(text): +def netmask_from_cidr(prefix): """ Take CIDR prefix and convert the prefix length to a "subnet mask". Example: - 192.0.2.0/24 -> 255.255.255.0 - 2001:db8::/48 -> ffff:ffff:ffff:: """ from ipaddress import ip_network - return str(ip_network(text).netmask) + return str(ip_network(prefix).netmask) + +@register_filter('netmask_from_ipv4') +def netmask_from_ipv4(address): + """ Take IP address and search all attached interface IP addresses for the + given one. After address has been found, return the associated netmask. + + Example: + - 172.18.201.10 -> 255.255.255.128 + """ + from netifaces import interfaces, ifaddresses, AF_INET + for interface in interfaces(): + tmp = ifaddresses(interface) + if AF_INET in tmp: + for af_addr in tmp[AF_INET]: + if 'addr' in af_addr: + if af_addr['addr'] == address: + return af_addr['netmask'] + + raise ValueError + +@register_filter('network_from_ipv4') +def network_from_ipv4(address): + """ Take IP address and search all attached interface IP addresses for the + given one. After address has been found, return the associated network + address. + + Example: + - 172.18.201.10 has mask 255.255.255.128 -> network is 172.18.201.0 + """ + netmask = netmask_from_ipv4(address) + from ipaddress import ip_interface + cidr_prefix = ip_interface(f'{address}/{netmask}').network + return address_from_cidr(cidr_prefix) @register_filter('is_ip') def is_ip(addr): diff --git a/src/conf_mode/dhcp_server.py b/src/conf_mode/dhcp_server.py index 9be586cdf..1ab2d8d16 100755 --- a/src/conf_mode/dhcp_server.py +++ b/src/conf_mode/dhcp_server.py @@ -26,6 +26,7 @@ from vyos.template import render from vyos.util import call from vyos.util import dict_search from vyos.validate import is_subnet_connected +from vyos.validate import is_addr_assigned from vyos.xml import defaults from vyos import ConfigError from vyos import airbag @@ -246,10 +247,19 @@ def verify(dhcp): if net.overlaps(net2): raise ConfigError('Conflicting subnet ranges: "{net}" overlaps "{net2}"!') + for address in (dict_search('listen_address', dhcp) or []): + if is_addr_assigned(address): + listen_ok = True + # no need to probe further networks, we have one that is valid + continue + else: + raise ConfigError(f'listen-address "{address}" not configured on any interface') + + if not listen_ok: - raise ConfigError('DHCP server configuration error! None of the configured\n' \ - 'subnets have an appropriate primary IP address on any\n' - 'broadcast interface.') + 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!') return None |