diff options
| author | Christian Breunig <christian@breunig.cc> | 2024-01-10 18:28:18 +0100 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-10 18:28:18 +0100 | 
| commit | 085a15059755cd4724adfc8ffb64f35760c07e0f (patch) | |
| tree | 6066419954faa3bc5c8b883ef2376a435e9b969d /src | |
| parent | f00779b36af8e282b453bebb1c80e5e619d1e478 (diff) | |
| parent | 41913f4d1d63ddd39d9125b0140b8a33449c2cfb (diff) | |
| download | vyos-1x-085a15059755cd4724adfc8ffb64f35760c07e0f.tar.gz vyos-1x-085a15059755cd4724adfc8ffb64f35760c07e0f.zip | |
Merge pull request #2785 from sarthurdev/kea-options
dhcp: T3316: T5787: T5912: Extend scope of DHCP options, bugfixes
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/service_dhcp-server.py | 15 | ||||
| -rwxr-xr-x | src/migration-scripts/dhcp-server/8-to-9 | 69 | ||||
| -rwxr-xr-x | src/system/on-dhcp-event.sh | 65 | 
3 files changed, 137 insertions, 12 deletions
| diff --git a/src/conf_mode/service_dhcp-server.py b/src/conf_mode/service_dhcp-server.py index 7ebc560ba..ceaba019e 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 @@ -222,6 +223,7 @@ def verify(dhcp):              if 'static_mapping' in subnet_config:                  # Static mappings require just a MAC address (will use an IP from the dynamic pool if IP is not set) +                used_ips = []                  for mapping, mapping_config in subnet_config['static_mapping'].items():                      if 'ip_address' in mapping_config:                          if ip_address(mapping_config['ip_address']) not in ip_network(subnet): @@ -233,6 +235,11 @@ def verify(dhcp):                              raise ConfigError(f'Either MAC address or Client identifier (DUID) is required for '                                                f'static mapping "{mapping}" within shared-network "{network}, {subnet}"!') +                        if mapping_config['ip_address'] in used_ips: +                            raise ConfigError(f'Configured IP address for static mapping "{mapping}" exists on another static mapping') + +                        used_ips.append(mapping_config['ip_address']) +              # There must be one subnet connected to a listen interface.              # This only counts if the network itself is not disabled!              if 'disable' not in network_config: @@ -294,12 +301,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): diff --git a/src/migration-scripts/dhcp-server/8-to-9 b/src/migration-scripts/dhcp-server/8-to-9 new file mode 100755 index 000000000..908420c18 --- /dev/null +++ b/src/migration-scripts/dhcp-server/8-to-9 @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2024 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. + +# T3316: +# - Migrate dhcp options under new option node + +import sys +import re +from vyos.configtree import ConfigTree + +if len(sys.argv) < 2: +    print("Must specify file name!") +    sys.exit(1) + +file_name = sys.argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +base = ['service', 'dhcp-server', 'shared-network-name'] +config = ConfigTree(config_file) + +if not config.exists(base): +    # Nothing to do +    sys.exit(0) + +option_nodes = ['bootfile-name', 'bootfile-server', 'bootfile-size', 'captive-portal', +                'client-prefix-length', 'default-router', 'domain-name', 'domain-search', +                'name-server', 'ip-forwarding', 'ipv6-only-preferred', 'ntp-server', +                'pop-server', 'server-identifier', 'smtp-server', 'static-route', +                'tftp-server-name', 'time-offset', 'time-server', 'time-zone', +                'vendor-option', 'wins-server', 'wpad-url'] + +for network in config.list_nodes(base): +    for option in option_nodes: +        if config.exists(base + [network, option]): +            config.set(base + [network, 'option']) +            config.copy(base + [network, option], base + [network, 'option', option]) +            config.delete(base + [network, option]) + +    if config.exists(base + [network, 'subnet']): +        for subnet in config.list_nodes(base + [network, 'subnet']): +            base_subnet = base + [network, 'subnet', subnet] +             +            for option in option_nodes: +                if config.exists(base + [network, 'subnet', subnet, option]): +                    config.set(base + [network, 'subnet', subnet, 'option']) +                    config.copy(base + [network, 'subnet', subnet, option], base + [network, 'subnet', subnet, 'option', option]) +                    config.delete(base + [network, 'subnet', subnet, option]) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print("Failed to save the modified config: {}".format(e)) +    exit(1) diff --git a/src/system/on-dhcp-event.sh b/src/system/on-dhcp-event.sh index 03574bdc3..e1a9f1884 100755 --- a/src/system/on-dhcp-event.sh +++ b/src/system/on-dhcp-event.sh @@ -15,28 +15,71 @@ if [ $# -lt 1 ]; then  fi  action=$1 -client_name=$LEASE4_HOSTNAME -client_ip=$LEASE4_ADDRESS -client_mac=$LEASE4_HWADDR  hostsd_client="/usr/bin/vyos-hostsd-client" -case "$action" in -  lease4_renew|lease4_recover) # add mapping for new/recovered lease address -    if [ -z "$client_name" ]; then -        logger -s -t on-dhcp-event "Client name was empty, using MAC \"$client_mac\" instead" -        client_name=$(echo "host-$client_mac" | tr : -) -    fi +get_subnet_domain_name () { +  python3 <<EOF +from vyos.kea import kea_get_active_config +from vyos.utils.dict import dict_search_args + +config = kea_get_active_config('4') +shared_networks = dict_search_args(config, 'arguments', f'Dhcp4', 'shared-networks') + +found = False -    $hostsd_client --add-hosts "$client_name,$client_ip" --tag "dhcp-server-$client_ip" --apply +if shared_networks: +  for network in shared_networks: +    for subnet in network[f'subnet4']: +      if subnet['id'] == $1: +        for option in subnet['option-data']: +          if option['name'] == 'domain-name': +            print(option['data']) +            found = True + +        if not found: +          for option in network['option-data']: +            if option['name'] == 'domain-name': +              print(option['data']) +EOF +} + +case "$action" in +  lease4_renew|lease4_recover)      exit 0      ;;    lease4_release|lease4_expire|lease4_decline) # delete mapping for released/declined address +    client_ip=$LEASE4_ADDRESS      $hostsd_client --delete-hosts --tag "dhcp-server-$client_ip" --apply      exit 0      ;; -  leases4_committed) # nothing to do +  leases4_committed) # process committed leases (added/renewed/recovered) +    for ((i = 0; i < $LEASES4_SIZE; i++)); do +      client_ip_var="LEASES4_AT${i}_ADDRESS" +      client_mac_var="LEASES4_AT${i}_HWADDR" +      client_name_var="LEASES4_AT${i}_HOSTNAME" +      client_subnet_id_var="LEASES4_AT${i}_SUBNET_ID" + +      client_ip=${!client_ip_var} +      client_mac=${!client_mac_var} +      client_name=${!client_name_var} +      client_subnet_id=${!client_subnet_id_var} + +      if [ -z "$client_name" ]; then +          logger -s -t on-dhcp-event "Client name was empty, using MAC \"$client_mac\" instead" +          client_name=$(echo "host-$client_mac" | tr : -) +      fi + +      client_domain=$(get_subnet_domain_name $client_subnet_id) + +      if [ -n "$client_domain" ]; then +        client_name="$client_name.$client_domain" +      fi + +      $hostsd_client --add-hosts "$client_name,$client_ip" --tag "dhcp-server-$client_ip" --apply +    done +      exit 0      ;; | 
