diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/interfaces-pppoe.py | 60 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-tunnel.py | 9 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-wirelessmodem.py | 76 | ||||
| -rwxr-xr-x | src/migration-scripts/quagga/5-to-6 | 63 | ||||
| -rwxr-xr-x | src/validators/mac-address | 18 | ||||
| -rwxr-xr-x | src/validators/vrf-name | 40 | 
6 files changed, 199 insertions, 67 deletions
| diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py index f318614db..d432377e8 100755 --- a/src/conf_mode/interfaces-pppoe.py +++ b/src/conf_mode/interfaces-pppoe.py @@ -20,12 +20,10 @@ from sys import exit  from copy import deepcopy  from jinja2 import Template  from subprocess import Popen, PIPE -from pwd import getpwnam -from grp import getgrnam -from stat import S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IXGRP, S_IROTH, S_IXOTH  from vyos.config import Config  from vyos.ifconfig import Interface +from vyos.util import chown_file, chmod_x_file  from vyos import ConfigError  from netifaces import interfaces @@ -150,12 +148,12 @@ echo 1 > /proc/sys/net/ipv6/conf/{{ intf }}/autoconfigure  {% endif %}  """ -config_pppoe_ip_pre_up_tmpl = """#!/bin/sh +config_pppoe_ip_up_tmpl = """#!/bin/sh  # As PPPoE is an "on demand" interface we need to re-configure it when it  # becomes up -if [ "$6" != "pppoe0" ]; then +if [ "$6" != "{{ intf }}" ]; then      exit  fi @@ -306,60 +304,47 @@ def verify(pppoe):  def generate(pppoe):      config_file_pppoe = f"/etc/ppp/peers/{pppoe['intf']}" -    ip_pre_up_script_file = f"/etc/ppp/ip-pre-up.d/9999-vyos-vrf-{pppoe['intf']}" +    ip_up_script_file = f"/etc/ppp/ip-up.d/9990-vyos-vrf-{pppoe['intf']}"      ipv6_if_up_script_file = f"/etc/ppp/ipv6-up.d/50-vyos-{pppoe['intf']}-autoconf" +    config_files = [config_file_pppoe, ip_up_script_file, ipv6_if_up_script_file] + +    # Ensure directories for config files exist - otherwise create them on demand +    for file in config_files: +        dirname = os.path.dirname(file) +        if not os.path.isdir(dirname): +            os.mkdir(dirname) +      # Always hang-up PPPoE connection prior generating new configuration file      cmd = f"systemctl stop ppp@{pppoe['intf']}.service"      subprocess_cmd(cmd)      if pppoe['deleted']:          # Delete PPP configuration files -        if os.path.exists(config_file_pppoe): -            os.unlink(config_file_pppoe) - -        if os.path.exists(ipv6_if_up_script_file): -            os.unlink(ipv6_if_up_script_file) - -        if os.path.exists(ip_pre_up_script_file): -            os.unlink(ip_pre_up_script_file) +        for file in config_files: +            if os.path.exists(file): +                os.unlink(file)      else: -        # PPP peers directory -        dirname = os.path.dirname(config_file_pppoe) -        if not os.path.isdir(dirname): -            os.mkdir(dirname) -          # Create PPP configuration files          tmpl = Template(config_pppoe_tmpl)          config_text = tmpl.render(pppoe)          with open(config_file_pppoe, 'w') as f:              f.write(config_text) -        # PPP ip-pre-up.d scripting directory -        dirname = os.path.dirname(ip_pre_up_script_file) -        if not os.path.isdir(dirname): -            os.mkdir(dirname) - -        tmpl = Template(config_pppoe_ip_pre_up_tmpl) +        tmpl = Template(config_pppoe_ip_up_tmpl)          config_text = tmpl.render(pppoe) -        with open(ip_pre_up_script_file, 'w') as f: +        with open(ip_up_script_file, 'w') as f:              f.write(config_text) -        # PPP ipv6-up.d scripting directory -        dirname = os.path.dirname(ipv6_if_up_script_file) -        if not os.path.isdir(dirname): -            os.mkdir(dirname) -          tmpl = Template(config_pppoe_ipv6_up_tmpl)          config_text = tmpl.render(pppoe)          with open(ipv6_if_up_script_file, 'w') as f:              f.write(config_text) -        bitmask = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | \ -                  S_IROTH | S_IXOTH -        os.chmod(ip_pre_up_script_file, bitmask) -        os.chmod(ipv6_if_up_script_file, bitmask) +        # make generated script file executable +        chmod_x_file(ip_up_script_file) +        chmod_x_file(ipv6_if_up_script_file)      return None @@ -374,10 +359,7 @@ def apply(pppoe):          subprocess_cmd(cmd)          # make logfile owned by root / vyattacfg -        if os.path.isfile(pppoe['logfile']): -            uid = getpwnam('root').pw_uid -            gid = getgrnam('vyattacfg').gr_gid -            os.chown(pppoe['logfile'], uid, gid) +        chown_file(pppoe['logfile'], 'root', 'vyattacfg')      return None diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py index 4cbb51f4a..646e61c53 100755 --- a/src/conf_mode/interfaces-tunnel.py +++ b/src/conf_mode/interfaces-tunnel.py @@ -138,6 +138,9 @@ default_config_data = {      'ip': False,      'ipv6': False,      'nhrp': [], +    'ipv6_autoconf': 0, +    'ipv6_forwarding': 1, +    'ipv6_dad_transmits': 1,      # internal      'tunnel': {},      # the following names are exactly matching the name @@ -183,6 +186,9 @@ mapping = {      'link_detect':         ('disable-link-detect', False, 2),      'vrf':                 ('vrf', False, None),      'addresses-add':       ('address', True, None), +    'ipv6_autoconf':       ('ipv6 address autoconf', False, 1), +    'ipv6_forwarding':     ('ipv6 disable-forwarding', False, 0), +    'ipv6_dad_transmits:': ('ipv6 dup-addr-detect-transmits', False, None)  }  def get_class (options): @@ -468,7 +474,8 @@ def apply(conf):          tunnel.set_interface(option, options[option])      # set other interface properties -    for option in ('alias', 'mtu', 'link_detect', 'multicast', 'allmulticast', 'vrf'): +    for option in ('alias', 'mtu', 'link_detect', 'multicast', 'allmulticast', +                   'vrf', 'ipv6_autoconf', 'ipv6_forwarding', 'ipv6_dad_transmits'):          tunnel.set_interface(option, options[option])      # Configure interface address(es) diff --git a/src/conf_mode/interfaces-wirelessmodem.py b/src/conf_mode/interfaces-wirelessmodem.py index 9efad3b8d..4b681a018 100755 --- a/src/conf_mode/interfaces-wirelessmodem.py +++ b/src/conf_mode/interfaces-wirelessmodem.py @@ -20,10 +20,10 @@ from sys import exit  from copy import deepcopy  from jinja2 import Template  from subprocess import Popen, PIPE -from pwd import getpwnam -from grp import getgrnam +from netifaces import interfaces  from vyos.config import Config +from vyos.util import chown_file, chmod_x_file  from vyos import ConfigError  # Please be careful if you edit the template. @@ -70,6 +70,30 @@ CONNECT ''  """ +config_wwan_ip_pre_up_tmpl = """#!/bin/sh +# As PPPoE is an "on demand" interface we need to re-configure it when it +# becomes 'up' + +ipparam=$6 + +# device name and metric are received using ipparam +device=`echo "$ipparam"|awk '{ print $1 }'` + +if [ "$device" != "{{ intf }}" ]; then +    exit +fi + +# add some info to syslog +DIALER_PID=$(cat /var/run/{{ intf }}.pid) +logger -t pppd[$DIALER_PID] "executing $0" + +{% if vrf -%} +logger -t pppd[$DIALER_PID] "configuring interface {{ intf }} for VRF {{ vrf }}" +ip link set dev {{ intf }} master {{ vrf }} +{% endif %} + +""" +  default_config_data = {      'address': [],      'apn': '', @@ -84,7 +108,8 @@ default_config_data = {      'metric': '10',      'mtu': '1500',      'name_server': True, -    'intf': '' +    'intf': '', +    'vrf': ''  }  def subprocess_cmd(command): @@ -154,6 +179,10 @@ def get_config():      if conf.exists(['ondemand']):          wwan['on_demand'] = True +    # retrieve VRF instance +    if conf.exists('vrf'): +        wwan['vrf'] = conf.return_value(['vrf']) +      return wwan  def verify(wwan): @@ -168,10 +197,24 @@ def verify(wwan):      if not os.path.exists(f"/dev/{wwan['device']}"):          raise ConfigError(f"Device {wwan['device']} does not exist") +    vrf_name = wwan['vrf'] +    if vrf_name and vrf_name not in interfaces(): +        raise ConfigError(f'VRF {vrf_name} does not exist') +      return None  def generate(wwan):      config_file_wwan = f"/etc/ppp/peers/{wwan['intf']}" +    config_file_wwan_chat = wwan['chat_script'] +    ip_up_script_file = f"/etc/ppp/ip-up.d/9991-vyos-vrf-{wwan['intf']}" + +    config_files = [config_file_wwan, config_file_wwan_chat, ip_up_script_file] + +    # Ensure directories for config files exist - otherwise create them on demand +    for file in config_files: +        dirname = os.path.dirname(file) +        if not os.path.isdir(dirname): +            os.mkdir(dirname)      # Always hang-up WWAN connection prior generating new configuration file      cmd = f"systemctl stop ppp@{wwan['intf']}.service" @@ -179,30 +222,32 @@ def generate(wwan):      if wwan['deleted']:          # Delete PPP configuration files -        if os.path.exists(config_file_wwan): -            os.unlink(config_file_wwan) -        if os.path.exists(wwan['chat_script']): -            os.unlink(wwan['chat_script']) +        for file in config_files: +            if os.path.exists(file): +                os.unlink(file)      else: -        # PPP peers directory -        dirname = os.path.dirname(config_file_wwan) -        if not os.path.isdir(dirname): -            os.mkdir(dirname) -          # Create PPP configuration files          tmpl = Template(config_wwan_tmpl)          config_text = tmpl.render(wwan)          with open(config_file_wwan, 'w') as f:              f.write(config_text) -          # Create PPP chat script          tmpl = Template(chat_wwan_tmpl)          config_text = tmpl.render(wwan)          with open(wwan['chat_script'], 'w') as f:              f.write(config_text) +        # Create ip-pre-up script +        tmpl = Template(config_wwan_ip_pre_up_tmpl) +        config_text = tmpl.render(wwan) +        with open(ip_up_script_file, 'w') as f: +            f.write(config_text) + +        # make generated script file executable +        chmod_x_file(ip_up_script_file) +      return None  def apply(wwan): @@ -216,10 +261,7 @@ def apply(wwan):          subprocess_cmd(cmd)          # make logfile owned by root / vyattacfg -        if os.path.isfile(wwan['logfile']): -            uid = getpwnam('root').pw_uid -            gid = getgrnam('vyattacfg').gr_gid -            os.chown(wwan['logfile'], uid, gid) +        chown_file(wwan['logfile'], 'root', 'vyattacfg')      return None diff --git a/src/migration-scripts/quagga/5-to-6 b/src/migration-scripts/quagga/5-to-6 new file mode 100755 index 000000000..a71851942 --- /dev/null +++ b/src/migration-scripts/quagga/5-to-6 @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 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/>. + +# * Remove parameter 'disable-network-import-check' which, as implemented, +#   had no effect on boot. + +import sys + +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() + +config = ConfigTree(config_file) + +if not config.exists(['protocols', 'bgp']): +    # Nothing to do +    sys.exit(0) +else: +    # Check if BGP is actually configured and obtain the ASN +    asn_list = config.list_nodes(['protocols', 'bgp']) +    if asn_list: +        # There's always just one BGP node, if any +        asn = asn_list[0] +    else: +        # There's actually no BGP, just its empty shell +        sys.exit(0) + +    # Check if BGP parameter disable-network-import-check exists +    param = ['protocols', 'bgp', asn, 'parameters', 'disable-network-import-check'] +    if config.exists(param): +        # Delete parameter +        config.delete(param) +    else: +        # Do nothing +        sys.exit(0) + +    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/validators/mac-address b/src/validators/mac-address index d6ec6d712..435920b84 100755 --- a/src/validators/mac-address +++ b/src/validators/mac-address @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2018 VyOS maintainers and contributors +# Copyright (C) 2018-2020 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 @@ -13,16 +13,14 @@  #  # 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 sys  import re +from sys import exit, argv -if len(sys.argv) == 2: -  pattern = "^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$" -  if re.match(pattern, sys.argv[1]): -    sys.exit(0) -  else: -    sys.exit(1) +if len(argv) == 2: +    pattern = "^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$" +    if re.match(pattern, argv[1]): +        exit(0) +    else: +        exit(1) diff --git a/src/validators/vrf-name b/src/validators/vrf-name new file mode 100755 index 000000000..11c453f4d --- /dev/null +++ b/src/validators/vrf-name @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 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 re +from sys import exit, argv + +if len(argv) == 2: +    len = len(argv[1]) +    # VRF instance name must be 16 characters or less, python range needs to be +    # extended by one +    if not len in range(1, 17): +        exit(1) + +    # Treat loopback interface "lo" explicitly. Adding "lo" explicitly to the +    # following regex pattern would deny any VRF name starting with lo - thuse +    # local-vrf would be illegal - and that we do not want. +    if argv[1] == "lo": +        exit(1) + +    # VRF instances should not be named after regular interface names like bond0, +    # br10 and so on - this can cause a lot of confusion/trouble +    pattern = "^(?!(bond|br|dum|eth|lan|eno|ens|enp|enx|gnv|ipoe|l2tp|l2tpeth|" \ +              "vtun|ppp|pppoe|peth|tun|vti|vxlan|wg|wlan|wlm)\d+(\.\d+(v.+)?)?$).*$" +    if re.match(pattern, argv[1]): +        exit(0) + +exit(1) | 
