diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/dns_dynamic.py | 24 | ||||
| -rwxr-xr-x | src/conf_mode/protocols_bgp.py | 1 | ||||
| -rwxr-xr-x | src/conf_mode/protocols_segment_routing.py | 74 | ||||
| -rwxr-xr-x | src/migration-scripts/nat/6-to-7 | 8 | ||||
| -rwxr-xr-x | src/op_mode/dhcp.py | 10 | ||||
| -rwxr-xr-x | src/op_mode/image_installer.py | 3 | ||||
| -rwxr-xr-x | src/validators/bgp-large-community-list | 8 | 
7 files changed, 107 insertions, 21 deletions
diff --git a/src/conf_mode/dns_dynamic.py b/src/conf_mode/dns_dynamic.py index c4dcb76ed..809c650d9 100755 --- a/src/conf_mode/dns_dynamic.py +++ b/src/conf_mode/dns_dynamic.py @@ -30,6 +30,9 @@ airbag.enable()  config_file = r'/run/ddclient/ddclient.conf'  systemd_override = r'/run/systemd/system/ddclient.service.d/override.conf' +# Dynamic interfaces that might not exist when the configuration is loaded +dynamic_interfaces = ('pppoe', 'sstpc') +  # Protocols that require zone  zone_necessary = ['cloudflare', 'digitalocean', 'godaddy', 'hetzner', 'gandi',                    'nfsn', 'nsupdate'] @@ -86,17 +89,19 @@ def verify(dyndns):              if field not in config:                  raise ConfigError(f'"{field.replace("_", "-")}" {error_msg_req}') -        # If dyndns address is an interface, ensure that it exists +        # If dyndns address is an interface, ensure +        # that the interface exists (or just warn if dynamic interface)          # and that web-options are not set          if config['address'] != 'web':              # exclude check interface for dynamic interfaces -            interface_filter = ('pppoe', 'sstpc') -            if config['address'].startswith(interface_filter): -                Warning(f'interface {config["address"]} does not exist!') +            if config['address'].startswith(dynamic_interfaces): +                Warning(f'Interface "{config["address"]}" does not exist yet and cannot ' +                        f'be used for Dynamic DNS service "{service}" until it is up!')              else:                  verify_interface_exists(config['address'])              if 'web_options' in config: -                raise ConfigError(f'"web-options" is applicable only when using HTTP(S) web request to obtain the IP address') +                raise ConfigError(f'"web-options" is applicable only when using HTTP(S) ' +                                  f'web request to obtain the IP address')          # RFC2136 uses 'key' instead of 'password'          if config['protocol'] != 'nsupdate' and 'password' not in config: @@ -124,13 +129,16 @@ def verify(dyndns):          if config['ip_version'] == 'both':              if config['protocol'] not in dualstack_supported: -                raise ConfigError(f'Both IPv4 and IPv6 at the same time {error_msg_uns} with protocol "{config["protocol"]}"') +                raise ConfigError(f'Both IPv4 and IPv6 at the same time {error_msg_uns} ' +                                  f'with protocol "{config["protocol"]}"')              # dyndns2 protocol in ddclient honors dual stack only for dyn.com (dyndns.org)              if config['protocol'] == 'dyndns2' and 'server' in config and config['server'] not in dyndns_dualstack_servers: -                raise ConfigError(f'Both IPv4 and IPv6 at the same time {error_msg_uns} for "{config["server"]}" with protocol "{config["protocol"]}"') +                raise ConfigError(f'Both IPv4 and IPv6 at the same time {error_msg_uns} ' +                                  f'for "{config["server"]}" with protocol "{config["protocol"]}"')          if {'wait_time', 'expiry_time'} <= config.keys() and int(config['expiry_time']) < int(config['wait_time']): -                raise ConfigError(f'"expiry-time" must be greater than "wait-time" for Dynamic DNS service "{service}"') +                raise ConfigError(f'"expiry-time" must be greater than "wait-time" for ' +                                  f'Dynamic DNS service "{service}"')      return None diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 00015023c..557f0a9e9 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -93,6 +93,7 @@ def get_config(config=None):      tmp = conf.get_config_dict(['policy'])      # Merge policy dict into "regular" config dict      bgp = dict_merge(tmp, bgp) +      return bgp diff --git a/src/conf_mode/protocols_segment_routing.py b/src/conf_mode/protocols_segment_routing.py new file mode 100755 index 000000000..eb1653212 --- /dev/null +++ b/src/conf_mode/protocols_segment_routing.py @@ -0,0 +1,74 @@ +#!/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/>. + +import os + +from sys import exit + +from vyos.config import Config +from vyos.template import render_to_string +from vyos import ConfigError +from vyos import frr +from vyos import airbag +airbag.enable() + +def get_config(config=None): +    if config: +        conf = config +    else: +        conf = Config() + +    base = ['protocols', 'segment-routing'] +    sr = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True) + +    # We have gathered the dict representation of the CLI, but there are default +    # options which we need to update into the dictionary retrived. +    sr = conf.merge_defaults(sr, recursive=True) + +    return sr + +def verify(static): +    return None + +def generate(static): +    if not static: +        return None + +    static['new_frr_config'] = render_to_string('frr/zebra.segment_routing.frr.j2', static) +    return None + +def apply(static): +    zebra_daemon = 'zebra' + +    # Save original configuration prior to starting any commit actions +    frr_cfg = frr.FRRConfig() +    frr_cfg.load_configuration(zebra_daemon) +    frr_cfg.modify_section(r'^segment-routing') +    if 'new_frr_config' in static: +        frr_cfg.add_before(frr.default_add_before, static['new_frr_config']) +    frr_cfg.commit_configuration(zebra_daemon) + +    return None + +if __name__ == '__main__': +    try: +        c = get_config() +        verify(c) +        generate(c) +        apply(c) +    except ConfigError as e: +        print(e) +        exit(1) diff --git a/src/migration-scripts/nat/6-to-7 b/src/migration-scripts/nat/6-to-7 index b5f6328ef..a2e735394 100755 --- a/src/migration-scripts/nat/6-to-7 +++ b/src/migration-scripts/nat/6-to-7 @@ -21,6 +21,7 @@  # to  #   'set nat [source|destination] rule X [inbound-interface|outbound interface] name <iface>'  #   'set nat [source|destination] rule X [inbound-interface|outbound interface] group <iface_group>' +# Also remove command if interface == any  from sys import argv,exit  from vyos.configtree import ConfigTree @@ -56,8 +57,11 @@ for direction in ['source', 'destination']:              if config.exists(base + [iface]):                  if config.exists(base + [iface, 'interface-name']):                      tmp = config.return_value(base + [iface, 'interface-name']) -                    config.delete(base + [iface, 'interface-name']) -                    config.set(base + [iface, 'name'], value=tmp) +                    if tmp != 'any': +                        config.delete(base + [iface, 'interface-name']) +                        config.set(base + [iface, 'name'], value=tmp) +                    else: +                        config.delete(base + [iface])  try:      with open(file_name, 'w') as f: diff --git a/src/op_mode/dhcp.py b/src/op_mode/dhcp.py index bd2c522ca..a9271ea79 100755 --- a/src/op_mode/dhcp.py +++ b/src/op_mode/dhcp.py @@ -102,11 +102,11 @@ def _get_raw_server_leases(family='inet', pool=None, sorted=None, state=[], orig          if family == 'inet':              data_lease['mac'] = lease['hwaddr'] -            data_lease['start'] = lease['start_timestamp'] +            data_lease['start'] = lease['start_timestamp'].timestamp()              data_lease['hostname'] = lease['hostname']          if family == 'inet6': -            data_lease['last_communication'] = lease['start_timestamp'] +            data_lease['last_communication'] = lease['start_timestamp'].timestamp()              data_lease['iaid_duid'] = _format_hex_string(lease['duid'])              lease_types_long = {'0': 'non-temporary', '1': 'temporary', '2': 'prefix delegation'}              data_lease['type'] = lease_types_long[lease['lease_type']] @@ -123,7 +123,7 @@ def _get_raw_server_leases(family='inet', pool=None, sorted=None, state=[], orig          # Do not add old leases          if data_lease['remaining'] != '' and data_lease['pool'] in pool and data_lease['state'] != 'free': -            if not state or data_lease['state'] in state: +            if not state or state == 'all' or data_lease['state'] in state:                  data.append(data_lease)          # deduplicate @@ -151,7 +151,7 @@ def _get_formatted_server_leases(raw_data, family='inet'):              ipaddr = lease.get('ip')              hw_addr = lease.get('mac')              state = lease.get('state') -            start = lease.get('start').timestamp() +            start = lease.get('start')              start =  _utc_to_local(start).strftime('%Y/%m/%d %H:%M:%S')              end = lease.get('end')              end =  _utc_to_local(end).strftime('%Y/%m/%d %H:%M:%S') if end else '-' @@ -168,7 +168,7 @@ def _get_formatted_server_leases(raw_data, family='inet'):          for lease in raw_data:              ipaddr = lease.get('ip')              state = lease.get('state') -            start = lease.get('last_communication').timestamp() +            start = lease.get('last_communication')              start =  _utc_to_local(start).strftime('%Y/%m/%d %H:%M:%S')              end = lease.get('end')              end =  _utc_to_local(end).strftime('%Y/%m/%d %H:%M:%S') diff --git a/src/op_mode/image_installer.py b/src/op_mode/image_installer.py index 8e01a9ea4..66ce8f2e6 100755 --- a/src/op_mode/image_installer.py +++ b/src/op_mode/image_installer.py @@ -612,7 +612,8 @@ def install_image() -> None:          print(MSG_WARN_IMAGE_NAME_WRONG)      # ask for password -    user_password: str = ask_input(MSG_INPUT_PASSWORD, default='vyos') +    user_password: str = ask_input(MSG_INPUT_PASSWORD, default='vyos', +                                   no_echo=True)      # ask for default console      console_type: str = ask_input(MSG_INPUT_CONSOLE_TYPE, diff --git a/src/validators/bgp-large-community-list b/src/validators/bgp-large-community-list index 80112dfdc..9ba5b27eb 100755 --- a/src/validators/bgp-large-community-list +++ b/src/validators/bgp-large-community-list @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-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 @@ -17,9 +17,8 @@  import re  import sys -from vyos.template import is_ipv4 -  pattern = '(.*):(.*):(.*)' +allowedChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '+', '*', '?', '^', '$', '(', ')', '[', ']', '{', '}', '|', '\\', ':', '-' }  if __name__ == '__main__':      if len(sys.argv) != 2: @@ -29,8 +28,7 @@ if __name__ == '__main__':      if not len(value) == 3:          sys.exit(1) -    if not (re.match(pattern, sys.argv[1]) and -           (is_ipv4(value[0]) or value[0].isdigit()) and (value[1].isdigit() or value[1] == '*')): +    if not (re.match(pattern, sys.argv[1]) and set(sys.argv[1]).issubset(allowedChars)):          sys.exit(1)      sys.exit(0)  | 
