diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/interfaces-openvpn.py | 68 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-wwan.py | 1 | ||||
| -rwxr-xr-x | src/conf_mode/ntp.py | 34 | ||||
| -rwxr-xr-x | src/conf_mode/protocols_static.py | 2 | ||||
| -rw-r--r-- | src/etc/modprobe.d/openvpn.conf | 1 | ||||
| -rwxr-xr-x | src/migration-scripts/container/0-to-1 | 8 | ||||
| -rwxr-xr-x | src/migration-scripts/ntp/2-to-3 | 62 | ||||
| -rwxr-xr-x | src/op_mode/show_ntp.sh | 2 | 
8 files changed, 140 insertions, 38 deletions
| diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 607a19385..3bef9b8f6 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -56,6 +56,8 @@ from vyos.utils.list import is_list_equal  from vyos.utils.file import makedir  from vyos.utils.file import read_file  from vyos.utils.file import write_file +from vyos.utils.kernel import check_kmod +from vyos.utils.kernel import unload_kmod  from vyos.utils.process import call  from vyos.utils.permission import chown  from vyos.utils.process import cmd @@ -86,30 +88,45 @@ def get_config(config=None):          conf = Config()      base = ['interfaces', 'openvpn'] -    tmp_pki = conf.get_config_dict(['pki'], key_mangling=('-', '_'), -                                get_first_key=True, no_tag_node_value_mangle=True) -      ifname, openvpn = get_interface_dict(conf, base) - -    if 'deleted' not in openvpn: -        openvpn['pki'] = tmp_pki -        if is_node_changed(conf, base + [ifname, 'openvpn-option']): -            openvpn.update({'restart_required': {}}) - -        # We have to get the dict using 'get_config_dict' instead of 'get_interface_dict' -        # as 'get_interface_dict' merges the defaults in, so we can not check for defaults in there. -        tmp = conf.get_config_dict(base + [openvpn['ifname']], get_first_key=True) - -        # We have to cleanup the config dict, as default values could enable features -        # which are not explicitly enabled on the CLI. Example: server mfa totp -        # originate comes with defaults, which will enable the -        # totp plugin, even when not set via CLI so we -        # need to check this first and drop those keys -        if dict_search('server.mfa.totp', tmp) == None: -            del openvpn['server']['mfa'] -      openvpn['auth_user_pass_file'] = '/run/openvpn/{ifname}.pw'.format(**openvpn) +    if 'deleted' in openvpn: +        return openvpn + +    openvpn['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'), +                                        get_first_key=True, +                                        no_tag_node_value_mangle=True) + +    if is_node_changed(conf, base + [ifname, 'openvpn-option']): +        openvpn.update({'restart_required': {}}) +    if is_node_changed(conf, base + [ifname, 'enable-dco']): +        openvpn.update({'restart_required': {}}) + +    # We have to get the dict using 'get_config_dict' instead of 'get_interface_dict' +    # as 'get_interface_dict' merges the defaults in, so we can not check for defaults in there. +    tmp = conf.get_config_dict(base + [openvpn['ifname']], get_first_key=True) + +    # We have to cleanup the config dict, as default values could enable features +    # which are not explicitly enabled on the CLI. Example: server mfa totp +    # originate comes with defaults, which will enable the +    # totp plugin, even when not set via CLI so we +    # need to check this first and drop those keys +    if dict_search('server.mfa.totp', tmp) == None: +        del openvpn['server']['mfa'] + +    # OpenVPN Data-Channel-Offload (DCO) is a Kernel module. If loaded it applies to all +    # OpenVPN interfaces. Check if DCO is used by any other interface instance. +    tmp = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) +    for interface, interface_config in tmp.items(): +        # If one interface has DCO configured, enable it. No need to further check +        # all other OpenVPN interfaces. We must use a dedicated key to indicate +        # the Kernel module must be loaded or not. The per interface "offload.dco" +        # key is required per OpenVPN interface instance. +        if dict_search('offload.dco', interface_config) != None: +            openvpn['module_load_dco'] = {} +            break +      return openvpn  def is_ec_private_key(pki, cert_name): @@ -670,6 +687,15 @@ def apply(openvpn):          if interface in interfaces():              VTunIf(interface).remove() +    # dynamically load/unload DCO Kernel extension if requested +    dco_module = 'ovpn_dco_v2' +    if 'module_load_dco' in openvpn: +        check_kmod(dco_module) +    else: +        unload_kmod(dco_module) + +    # Now bail out early if interface is disabled or got deleted +    if 'deleted' in openvpn or 'disable' in openvpn:          return None      # verify specified IP address is present on any interface on this system diff --git a/src/conf_mode/interfaces-wwan.py b/src/conf_mode/interfaces-wwan.py index 6658ca86a..2515dc838 100755 --- a/src/conf_mode/interfaces-wwan.py +++ b/src/conf_mode/interfaces-wwan.py @@ -75,7 +75,6 @@ def get_config(config=None):      # We need to know the amount of other WWAN interfaces as ModemManager needs      # to be started or stopped. -    conf.set_level(base)      wwan['other_interfaces'] = conf.get_config_dict([], key_mangling=('-', '_'),                                                         get_first_key=True,                                                         no_tag_node_value_mangle=True) diff --git a/src/conf_mode/ntp.py b/src/conf_mode/ntp.py index 917f6e058..1cc23a7df 100755 --- a/src/conf_mode/ntp.py +++ b/src/conf_mode/ntp.py @@ -24,6 +24,7 @@ from vyos.utils.process import call  from vyos.utils.permission import chmod_750  from vyos.utils.network import get_interface_config  from vyos.template import render +from vyos.template import is_ipv4  from vyos import ConfigError  from vyos import airbag  airbag.enable() @@ -62,16 +63,29 @@ def verify(ntp):      if 'interface' in ntp:          # If ntpd should listen on a given interface, ensure it exists -        for interface in ntp['interface']: -            verify_interface_exists(interface) - -            # If we run in a VRF, our interface must belong to this VRF, too -            if 'vrf' in ntp: -                tmp = get_interface_config(interface) -                vrf_name = ntp['vrf'] -                if 'master' not in tmp or tmp['master'] != vrf_name: -                    raise ConfigError(f'NTP runs in VRF "{vrf_name}" - "{interface}" '\ -                                      f'does not belong to this VRF!') +        interface = ntp['interface'] +        verify_interface_exists(interface) + +        # If we run in a VRF, our interface must belong to this VRF, too +        if 'vrf' in ntp: +            tmp = get_interface_config(interface) +            vrf_name = ntp['vrf'] +            if 'master' not in tmp or tmp['master'] != vrf_name: +                raise ConfigError(f'NTP runs in VRF "{vrf_name}" - "{interface}" '\ +                                  f'does not belong to this VRF!') + +    if 'listen_address' in ntp: +        ipv4_addresses = 0 +        ipv6_addresses = 0 +        for address in ntp['listen_address']: +            if is_ipv4(address): +                ipv4_addresses += 1 +            else: +                ipv6_addresses += 1 +        if ipv4_addresses > 1: +            raise ConfigError(f'NTP Only admits one ipv4 value for listen-address parameter ') +        if ipv6_addresses > 1: +            raise ConfigError(f'NTP Only admits one ipv6 value for listen-address parameter ')      return None diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py index 7b6150696..5def8d645 100755 --- a/src/conf_mode/protocols_static.py +++ b/src/conf_mode/protocols_static.py @@ -47,7 +47,7 @@ def get_config(config=None):      base_path = ['protocols', 'static']      # eqivalent of the C foo ? 'a' : 'b' statement      base = vrf and ['vrf', 'name', vrf, 'protocols', 'static'] or base_path -    static = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) +    static = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True)      # Assign the name of our VRF context      if vrf: static['vrf'] = vrf diff --git a/src/etc/modprobe.d/openvpn.conf b/src/etc/modprobe.d/openvpn.conf new file mode 100644 index 000000000..a9259fea2 --- /dev/null +++ b/src/etc/modprobe.d/openvpn.conf @@ -0,0 +1 @@ +blacklist ovpn-dco-v2 diff --git a/src/migration-scripts/container/0-to-1 b/src/migration-scripts/container/0-to-1 index 9fcf295e8..86f89ee04 100755 --- a/src/migration-scripts/container/0-to-1 +++ b/src/migration-scripts/container/0-to-1 @@ -39,12 +39,12 @@ config = ConfigTree(config_file)  if config.exists(base):      for container in config.list_nodes(base):          # Stop any given container first -        call(f'systemctl stop vyos-container-{container}.service') +        call(f'sudo systemctl stop vyos-container-{container}.service')          # Export container image for later re-import to new filesystem. We store          # the backup on a real disk as a tmpfs (like /tmp) could probably lack          # memory if a host has too many containers stored.          image_name = config.return_value(base + [container, 'image']) -        call(f'podman image save --quiet --output /root/{container}.tar --format oci-archive {image_name}') +        call(f'sudo podman image save --quiet --output /root/{container}.tar --format oci-archive {image_name}')  # No need to adjust the strage driver online (this is only used for testing and  # debugging on a live system) - it is already overlay2 when the migration script @@ -66,10 +66,10 @@ if config.exists(base):          # Export container image for later re-import to new filesystem          image_name = config.return_value(base + [container, 'image'])          image_path = f'/root/{container}.tar' -        call(f'podman image load --quiet --input {image_path}') +        call(f'sudo podman image load --quiet --input {image_path}')          # Start any given container first -        call(f'systemctl start vyos-container-{container}.service') +        call(f'sudo systemctl start vyos-container-{container}.service')          # Delete temporary container image          if os.path.exists(image_path): diff --git a/src/migration-scripts/ntp/2-to-3 b/src/migration-scripts/ntp/2-to-3 new file mode 100755 index 000000000..7d4e0bd83 --- /dev/null +++ b/src/migration-scripts/ntp/2-to-3 @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2023 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/>. + +# T5154: allow only one ip address per family for parameter 'listen-address' +# Allow only one interface for parameter 'interface' +# If more than one are specified, remove such entries + +import sys + +from vyos.configtree import ConfigTree +from vyos.template import is_ipv4 +from vyos.template import is_ipv6 + +if (len(sys.argv) < 1): +    print("Must specify file name!") +    sys.exit(1) + +file_name = sys.argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +config = ConfigTree(config_file) + +base_path = ['service', 'ntp'] +if not config.exists(base_path): +    # Nothing to do +    sys.exit(0) + +if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv4(addr)]) > 1): +    for addr in config.return_values(base_path + ['listen-address']): +        if is_ipv4(addr): +            config.delete_value(base_path + ['listen-address'], addr) + +if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv6(addr)]) > 1): +    for addr in config.return_values(base_path + ['listen-address']): +        if is_ipv6(addr): +            config.delete_value(base_path + ['listen-address'], addr) + +if config.exists(base_path + ['interface']): +    if len(config.return_values(base_path + ['interface'])) > 1: +        config.delete(base_path + ['interface']) + +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)) +    sys.exit(1) diff --git a/src/op_mode/show_ntp.sh b/src/op_mode/show_ntp.sh index 85f8eda15..4b59b801e 100755 --- a/src/op_mode/show_ntp.sh +++ b/src/op_mode/show_ntp.sh @@ -18,7 +18,7 @@ if ! ps -C chronyd &>/dev/null; then  fi  PID=$(pgrep chronyd | head -n1) -VRF_NAME=$(ip vrf identify ) +VRF_NAME=$(ip vrf identify ${PID})  if [ ! -z ${VRF_NAME} ]; then      VRF_CMD="sudo ip vrf exec ${VRF_NAME}" | 
