diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/interfaces-pseudo-ethernet.py | 9 | ||||
-rwxr-xr-x | src/conf_mode/ntp.py | 58 | ||||
-rwxr-xr-x | src/conf_mode/service_console-server.py | 109 | ||||
-rwxr-xr-x | src/conf_mode/service_router-advert.py | 19 | ||||
-rwxr-xr-x | src/conf_mode/snmp.py | 31 | ||||
-rwxr-xr-x | src/conf_mode/ssh.py | 10 | ||||
-rwxr-xr-x | src/conf_mode/system-login.py | 7 | ||||
-rwxr-xr-x | src/conf_mode/system-syslog.py | 51 | ||||
-rwxr-xr-x | src/conf_mode/system_console.py | 13 | ||||
-rwxr-xr-x | src/conf_mode/vpn_l2tp.py | 2 | ||||
-rw-r--r-- | src/etc/systemd/system/conserver-server.service.d/override.conf | 10 | ||||
-rw-r--r-- | src/etc/systemd/system/radvd.service.d/override.conf | 17 | ||||
-rw-r--r-- | src/etc/systemd/system/snmpd.service.d/override.conf | 6 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/5-to-6 | 18 | ||||
-rwxr-xr-x | src/migration-scripts/system/16-to-17 | 45 | ||||
-rwxr-xr-x | src/op_mode/show_interfaces.py | 13 | ||||
-rw-r--r-- | src/systemd/dhcp6c@.service | 3 | ||||
-rw-r--r-- | src/systemd/dropbear@.service | 14 | ||||
-rw-r--r-- | src/systemd/dropbearkey.service | 11 | ||||
-rw-r--r-- | src/tests/test_util.py | 34 | ||||
-rwxr-xr-x | src/validators/wireless-phy | 25 |
21 files changed, 387 insertions, 118 deletions
diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index b142688f6..70710e97c 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -46,17 +46,18 @@ default_config_data = { } def get_config(): + peth = deepcopy(default_config_data) + conf = Config() + # determine tagNode instance if 'VYOS_TAGNODE_VALUE' not in os.environ: raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified') - ifname = os.environ['VYOS_TAGNODE_VALUE'] - conf = Config() + peth['intf'] = os.environ['VYOS_TAGNODE_VALUE'] # Check if interface has been removed - cfg_base = ['interfaces', 'pseudo-ethernet', ifname] + cfg_base = ['interfaces', 'pseudo-ethernet', peth['intf']] if not conf.exists(cfg_base): - peth = deepcopy(default_config_data) peth['deleted'] = True return peth diff --git a/src/conf_mode/ntp.py b/src/conf_mode/ntp.py index a66fddc61..9180998aa 100755 --- a/src/conf_mode/ntp.py +++ b/src/conf_mode/ntp.py @@ -18,6 +18,7 @@ import os from copy import deepcopy from ipaddress import ip_network +from netifaces import interfaces from sys import exit from vyos.config import Config @@ -29,23 +30,27 @@ from vyos import airbag airbag.enable() config_file = r'/etc/ntp.conf' +systemd_override = r'/etc/systemd/system/ntp.service.d/override.conf' default_config_data = { 'servers': [], 'allowed_networks': [], - 'listen_address': [] + 'listen_address': [], + 'vrf': '' } def get_config(): ntp = deepcopy(default_config_data) conf = Config() - if not conf.exists('system ntp'): + base = ['system', 'ntp'] + if not conf.exists(base): return None else: - conf.set_level('system ntp') + conf.set_level(base) - if conf.exists('allow-clients address'): - networks = conf.return_values('allow-clients address') + node = ['allow-clients', 'address'] + if conf.exists(node): + networks = conf.return_values(node) for n in networks: addr = ip_network(n) net = { @@ -56,11 +61,13 @@ def get_config(): ntp['allowed_networks'].append(net) - if conf.exists('listen-address'): - ntp['listen_address'] = conf.return_values('listen-address') + node = ['listen-address'] + if conf.exists(node): + ntp['listen_address'] = conf.return_values(node) - if conf.exists('server'): - for node in conf.list_nodes('server'): + node = ['server'] + if conf.exists(node): + for node in conf.list_nodes(node): options = [] server = { "name": node, @@ -76,41 +83,50 @@ def get_config(): server['options'] = options ntp['servers'].append(server) + node = ['vrf'] + if conf.exists(node): + ntp['vrf'] = conf.return_value(node) + return ntp def verify(ntp): # bail out early - looks like removal from running config - if ntp is None: + if not ntp: return None # Configuring allowed clients without a server makes no sense if len(ntp['allowed_networks']) and not len(ntp['servers']): raise ConfigError('NTP server not configured') - for n in ntp['allowed_networks']: - try: - addr = ip_network( n['network'] ) - break - except ValueError: - raise ConfigError("{0} does not appear to be a valid IPv4 or IPv6 network, check host bits!".format(n['network'])) + if ntp['vrf'] and ntp['vrf'] not in interfaces(): + raise ConfigError('VRF "{vrf}" does not exist'.format(**ntp)) return None def generate(ntp): # bail out early - looks like removal from running config - if ntp is None: + if not ntp: return None render(config_file, 'ntp/ntp.conf.tmpl', ntp) + render(systemd_override, 'ntp/override.conf.tmpl', ntp, trim_blocks=True) + return None def apply(ntp): - if ntp is not None: - call('systemctl restart ntp.service') - else: + if not ntp: # NTP support is removed in the commit call('systemctl stop ntp.service') - os.unlink(config_file) + if os.path.exists(config_file): + os.unlink(config_file) + if os.path.isfile(systemd_override): + os.unlink(systemd_override) + + # Reload systemd manager configuration + call('systemctl daemon-reload') + + if ntp: + call('systemctl restart ntp.service') return None diff --git a/src/conf_mode/service_console-server.py b/src/conf_mode/service_console-server.py new file mode 100755 index 000000000..7f6967983 --- /dev/null +++ b/src/conf_mode/service_console-server.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +# +# 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 +# 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.configdict import dict_merge +from vyos.template import render +from vyos.util import call +from vyos import ConfigError + +config_file = r'/run/conserver/conserver.cf' + +# Default values are necessary until the implementation of T2588 is completed +default_values = { + 'data_bits': '8', + 'parity': 'none', + 'stop_bits': '1' +} + +def get_config(): + conf = Config() + base = ['service', 'console-server'] + + if not conf.exists(base): + return None + + # Retrieve CLI representation as dictionary + proxy = conf.get_config_dict(base, key_mangling=('-', '_')) + # The retrieved dictionary will look something like this: + # + # {'device': {'usb0b2.4p1.0': {'speed': '9600'}, + # 'usb0b2.4p1.1': {'data_bits': '8', + # 'parity': 'none', + # 'speed': '115200', + # 'stop_bits': '2'}}} + + # We have gathered the dict representation of the CLI, but there are default + # options which we need to update into the dictionary retrived. + for device in proxy['device'].keys(): + tmp = dict_merge(default_values, proxy['device'][device]) + proxy['device'][device] = tmp + + return proxy + +def verify(proxy): + if not proxy: + return None + + for device in proxy['device']: + keys = proxy['device'][device].keys() + if 'speed' not in keys: + raise ConfigError(f'Serial port speed must be defined for "{tmp}"!') + + if 'ssh' in keys: + ssh_keys = proxy['device'][device]['ssh'].keys() + if 'port' not in ssh_keys: + raise ConfigError(f'SSH port must be defined for "{tmp}"!') + + return None + +def generate(proxy): + if not proxy: + return None + + render(config_file, 'conserver/conserver.conf.tmpl', proxy) + return None + +def apply(proxy): + call('systemctl stop dropbear@*.service conserver-server.service') + + if not proxy: + if os.path.isfile(config_file): + os.unlink(config_file) + return None + + call('systemctl restart conserver-server.service') + + for device in proxy['device']: + if 'ssh' in proxy['device'][device].keys(): + port = proxy['device'][device]['ssh']['port'] + call(f'systemctl restart dropbear@{device}.service') + + 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/conf_mode/service_router-advert.py b/src/conf_mode/service_router-advert.py index da7019e2c..ef6148ebd 100755 --- a/src/conf_mode/service_router-advert.py +++ b/src/conf_mode/service_router-advert.py @@ -27,7 +27,7 @@ from vyos.template import render from vyos import airbag airbag.enable() -config_file = r'/etc/radvd.conf' +config_file = r'/run/radvd/radvd.conf' default_config_data = { 'interfaces': [] @@ -66,8 +66,8 @@ def get_config(): if conf.exists(['hop-limit']): intf['hop_limit'] = conf.return_value(['hop-limit']) - if conf.exists(['default-lifetim']): - intf['default_lifetime'] = conf.return_value(['default-lifetim']) + if conf.exists(['default-lifetime']): + intf['default_lifetime'] = conf.return_value(['default-lifetime']) if conf.exists(['default-preference']): intf['default_preference'] = conf.return_value(['default-preference']) @@ -107,8 +107,8 @@ def get_config(): 'prefix' : prefix, 'autonomous_flag' : 'on', 'on_link' : 'on', - 'preferred_lifetime': '14400', - 'valid_lifetime' : '2592000' + 'preferred_lifetime': 14400, + 'valid_lifetime' : 2592000 } @@ -122,10 +122,10 @@ def get_config(): tmp['on_link'] = 'off' if conf.exists(['preferred-lifetime']): - tmp['preferred_lifetime'] = conf.return_value(['preferred-lifetime']) + tmp['preferred_lifetime'] = int(conf.return_value(['preferred-lifetime'])) if conf.exists(['valid-lifetime']): - tmp['valid_lifetime'] = conf.return_value(['valid-lifetime']) + tmp['valid_lifetime'] = int(conf.return_value(['valid-lifetime'])) intf['prefixes'].append(tmp) @@ -134,6 +134,11 @@ def get_config(): return rtradv def verify(rtradv): + for interface in rtradv['interfaces']: + for prefix in interface['prefixes']: + if not (prefix['valid_lifetime'] > prefix['preferred_lifetime']): + raise ConfigError('Prefix valid-lifetime must be greater then preferred-lifetime') + return None def generate(rtradv): diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py index 2b6140f41..eb0d20654 100755 --- a/src/conf_mode/snmp.py +++ b/src/conf_mode/snmp.py @@ -17,8 +17,8 @@ import os from binascii import hexlify +from netifaces import interfaces from time import sleep -from stat import S_IRWXU, S_IXGRP, S_IXOTH, S_IROTH, S_IRGRP from sys import exit from vyos.config import Config @@ -36,6 +36,7 @@ config_file_daemon = r'/etc/snmp/snmpd.conf' config_file_access = r'/usr/share/snmp/snmpd.conf' config_file_user = r'/var/lib/snmp/snmpd.conf' default_script_dir = r'/config/user-data/' +systemd_override = r'/etc/systemd/system/snmpd.service.d/override.conf' # SNMP OIDs used to mark auth/priv type OIDs = { @@ -66,7 +67,8 @@ default_config_data = { 'v3_traps': [], 'v3_users': [], 'v3_views': [], - 'script_ext': [] + 'script_ext': [], + 'vrf': '' } def rmfile(file): @@ -174,9 +176,6 @@ def get_config(): snmp['trap_targets'].append(trap_tgt) - # - # 'set service snmp script-extensions' - # if conf.exists('script-extensions'): for extname in conf.list_nodes('script-extensions extension-name'): conf_script = conf.return_value('script-extensions extension-name {} script'.format(extname)) @@ -191,6 +190,10 @@ def get_config(): snmp['script_ext'].append(extension) + if conf.exists('vrf'): + snmp['vrf'] = conf.return_value('vrf') + + ######################################################################### # ____ _ _ __ __ ____ _____ # # / ___|| \ | | \/ | _ \ __ _|___ / # @@ -393,7 +396,7 @@ def verify(snmp): if not os.path.isfile(ext['script']): print ("WARNING: script: {} doesn't exist".format(ext['script'])) else: - os.chmod(ext['script'], S_IRWXU | S_IXGRP | S_IXOTH | S_IROTH | S_IRGRP) + chmod_755(ext['script']) for listen in snmp['listen_address']: addr = listen[0] @@ -413,6 +416,9 @@ def verify(snmp): else: print('WARNING: SNMP listen address {0} not configured!'.format(addr)) + if snmp['vrf'] and snmp['vrf'] not in interfaces(): + raise ConfigError('VRF "{vrf}" does not exist'.format(**snmp)) + # bail out early if SNMP v3 is not configured if not snmp['v3_enabled']: return None @@ -512,11 +518,14 @@ def generate(snmp): # This is even save if service is going to be removed call('systemctl stop snmpd.service') config_files = [config_file_client, config_file_daemon, config_file_access, - config_file_user] + config_file_user, systemd_override] for file in config_files: rmfile(file) - if snmp is None: + # Reload systemd manager configuration + call('systemctl daemon-reload') + + if not snmp: return None # Write client config file @@ -527,13 +536,17 @@ def generate(snmp): render(config_file_access, 'snmp/usr.snmpd.conf.tmpl', snmp) # Write access rights config file render(config_file_user, 'snmp/var.snmpd.conf.tmpl', snmp) + # Write daemon configuration file + render(systemd_override, 'snmp/override.conf.tmpl', snmp) return None def apply(snmp): - if snmp is None: + if not snmp: return None + # Reload systemd manager configuration + call('systemctl daemon-reload') # start SNMP daemon call("systemctl restart snmpd.service") diff --git a/src/conf_mode/ssh.py b/src/conf_mode/ssh.py index 5a0ae059b..43fa2ff39 100755 --- a/src/conf_mode/ssh.py +++ b/src/conf_mode/ssh.py @@ -31,7 +31,7 @@ config_file = r'/etc/ssh/sshd_config' systemd_override = r'/etc/systemd/system/ssh.service.d/override.conf' default_config_data = { - 'port' : '22', + 'port' : ['22'], 'log_level': 'INFO', 'password_authentication': 'yes', 'host_validation': 'yes', @@ -137,9 +137,11 @@ def apply(ssh): os.unlink(config_file) if os.path.isfile(systemd_override): os.unlink(systemd_override) - else: - # Reload systemd manager configuration - call('systemctl daemon-reload') + + # Reload systemd manager configuration + call('systemctl daemon-reload') + + if ssh: call('systemctl restart ssh.service') return None diff --git a/src/conf_mode/system-login.py b/src/conf_mode/system-login.py index 5990c3777..93d4cc679 100755 --- a/src/conf_mode/system-login.py +++ b/src/conf_mode/system-login.py @@ -144,7 +144,8 @@ def get_config(): 'disabled': False, 'key': '', 'port': '1812', - 'timeout': '2' + 'timeout': '2', + 'priority': 255 } conf.set_level(base_level + ['radius', 'server', server]) @@ -164,6 +165,10 @@ def get_config(): if conf.exists(['timeout']): server_cfg['timeout'] = conf.return_value(['timeout']) + # Check if RADIUS server has priority + if conf.exists(['priority']): + server_cfg['priority'] = int(conf.return_value(['priority'])) + # Append individual RADIUS server configuration to global server list login['radius_server'].append(server_cfg) diff --git a/src/conf_mode/system-syslog.py b/src/conf_mode/system-syslog.py index 8b20e1135..cfc1ca55f 100755 --- a/src/conf_mode/system-syslog.py +++ b/src/conf_mode/system-syslog.py @@ -162,32 +162,31 @@ def generate_selectors(c, config_node): # protocols and security are being mapped here # for backward compatibility with old configs # security and protocol mappings can be removed later - if c.is_tag(config_node): - nodes = c.list_nodes(config_node) - selectors = "" - for node in nodes: - lvl = c.return_value(config_node + ' ' + node + ' level') - if lvl == None: - lvl = "err" - if lvl == 'all': - lvl = '*' - if node == 'all' and node != nodes[-1]: - selectors += "*." + lvl + ";" - elif node == 'all': - selectors += "*." + lvl - elif node != nodes[-1]: - if node == 'protocols': - node = 'local7' - if node == 'security': - node = 'auth' - selectors += node + "." + lvl + ";" - else: - if node == 'protocols': - node = 'local7' - if node == 'security': - node = 'auth' - selectors += node + "." + lvl - return selectors + nodes = c.list_nodes(config_node) + selectors = "" + for node in nodes: + lvl = c.return_value(config_node + ' ' + node + ' level') + if lvl == None: + lvl = "err" + if lvl == 'all': + lvl = '*' + if node == 'all' and node != nodes[-1]: + selectors += "*." + lvl + ";" + elif node == 'all': + selectors += "*." + lvl + elif node != nodes[-1]: + if node == 'protocols': + node = 'local7' + if node == 'security': + node = 'auth' + selectors += node + "." + lvl + ";" + else: + if node == 'protocols': + node = 'local7' + if node == 'security': + node = 'auth' + selectors += node + "." + lvl + return selectors def generate(c): diff --git a/src/conf_mode/system_console.py b/src/conf_mode/system_console.py index 0831232fb..034cbee63 100755 --- a/src/conf_mode/system_console.py +++ b/src/conf_mode/system_console.py @@ -74,12 +74,15 @@ def generate(console): call(f'systemctl stop {basename}') os.unlink(os.path.join(root, basename)) + if not console: + return None + for device in console['device'].keys(): config_file = base_dir + f'/serial-getty@{device}.service' - render(config_file, 'getty/serial-getty.service.tmpl', console['device'][device]) + getty_wants_symlink = base_dir + f'/getty.target.wants/serial-getty@{device}.service' - # Reload systemd manager configuration - call('systemctl daemon-reload') + render(config_file, 'getty/serial-getty.service.tmpl', console['device'][device]) + os.symlink(config_file, getty_wants_symlink) # GRUB # For existing serial line change speed (if necessary) @@ -107,6 +110,10 @@ def generate(console): def apply(console): # reset screen blanking call('/usr/bin/setterm -blank 0 -powersave off -powerdown 0 -term linux </dev/tty1 >/dev/tty1 2>&1') + + # Reload systemd manager configuration + call('systemctl daemon-reload') + if not console: return None diff --git a/src/conf_mode/vpn_l2tp.py b/src/conf_mode/vpn_l2tp.py index febe8c3b7..7e40be32a 100755 --- a/src/conf_mode/vpn_l2tp.py +++ b/src/conf_mode/vpn_l2tp.py @@ -278,7 +278,7 @@ def get_config(): l2tp['lns_shared_secret'] = conf.return_value(['lns', 'shared-secret']) if conf.exists(['ccp-disable']): - l2tp[['ccp_disable']] = True + l2tp['ccp_disable'] = True # PPP options if conf.exists(['idle']): diff --git a/src/etc/systemd/system/conserver-server.service.d/override.conf b/src/etc/systemd/system/conserver-server.service.d/override.conf new file mode 100644 index 000000000..3c753f572 --- /dev/null +++ b/src/etc/systemd/system/conserver-server.service.d/override.conf @@ -0,0 +1,10 @@ +[Unit] +After= +After=vyos-router.service +ConditionPathExists=/run/conserver/conserver.cf + +[Service] +Type=simple +ExecStart= +ExecStart=/usr/sbin/conserver -M localhost -C /run/conserver/conserver.cf +Restart=on-failure diff --git a/src/etc/systemd/system/radvd.service.d/override.conf b/src/etc/systemd/system/radvd.service.d/override.conf new file mode 100644 index 000000000..44c4345e1 --- /dev/null +++ b/src/etc/systemd/system/radvd.service.d/override.conf @@ -0,0 +1,17 @@ +[Unit]
+ConditionPathExists=/run/radvd/radvd.conf
+After=
+After=vyos-router.service
+
+[Service]
+WorkingDirectory=
+WorkingDirectory=/run/radvd
+ExecStartPre=
+ExecStartPre=/usr/sbin/radvd --logmethod stderr_clean --configtest --config /run/radvd/radvd.conf
+ExecStart=
+ExecStart=/usr/sbin/radvd --logmethod stderr_clean --config /run/radvd/radvd.conf --pidfile /run/radvd/radvd.pid
+ExecReload=
+ExecReload=/usr/sbin/radvd --logmethod stderr_clean --configtest --config /run/radvd/radvd.conf
+ExecReload=/bin/kill -HUP $MAINPID
+PIDFile=
+PIDFile=/run/radvd/radvd.pid
diff --git a/src/etc/systemd/system/snmpd.service.d/override.conf b/src/etc/systemd/system/snmpd.service.d/override.conf deleted file mode 100644 index c366f9073..000000000 --- a/src/etc/systemd/system/snmpd.service.d/override.conf +++ /dev/null @@ -1,6 +0,0 @@ -[Service] -Environment= -Environment="MIBSDIR=/usr/share/snmp/mibs:/usr/share/snmp/mibs/iana:/usr/share/snmp/mibs/ietf:/usr/share/mibs/site:/usr/share/snmp/mibs:/usr/share/mibs/iana:/usr/share/mibs/ietf:/usr/share/mibs/netsnmp" -ExecStart= -ExecStart=/usr/sbin/snmpd -LS0-5d -Lf /dev/null -u Debian-snmp -g Debian-snmp -I -ipCidrRouteTable,inetCidrRouteTable -f -p /run/snmpd.pid - diff --git a/src/migration-scripts/interfaces/5-to-6 b/src/migration-scripts/interfaces/5-to-6 index 85a1994c6..1291751d8 100755 --- a/src/migration-scripts/interfaces/5-to-6 +++ b/src/migration-scripts/interfaces/5-to-6 @@ -59,13 +59,17 @@ def copy_rtradv(c, old_base, interface): prefix_base = new_base + ['prefix'] if c.exists(prefix_base): for prefix in config.list_nodes(prefix_base): - bool_cleanup = ['autonomous-flag', 'on-link-flag'] - for bool in bool_cleanup: - if c.exists(prefix_base + [prefix, bool]): - tmp = c.return_value(prefix_base + [prefix, bool]) - c.delete(prefix_base + [prefix, bool]) - if tmp == 'true': - c.set(prefix_base + [prefix, bool]) + if c.exists(prefix_base + [prefix, 'autonomous-flag']): + tmp = c.return_value(prefix_base + [prefix, 'autonomous-flag']) + c.delete(prefix_base + [prefix, 'autonomous-flag']) + if tmp == 'false': + c.set(prefix_base + [prefix, 'no-autonomous-flag']) + + if c.exists(prefix_base + [prefix, 'on-link-flag']): + tmp = c.return_value(prefix_base + [prefix, 'on-link-flag']) + c.delete(prefix_base + [prefix, 'on-link-flag']) + if tmp == 'true': + c.set(prefix_base + [prefix, 'on-link-flag']) # router advertisement can be individually disabled per interface # the node has been renamed from send-advert {true | false} to no-send-advert diff --git a/src/migration-scripts/system/16-to-17 b/src/migration-scripts/system/16-to-17 index 981149d1b..8f762c0e2 100755 --- a/src/migration-scripts/system/16-to-17 +++ b/src/migration-scripts/system/16-to-17 @@ -41,31 +41,32 @@ else: if config.exists(base + ['netconsole']): config.delete(base + ['netconsole']) - for device in config.list_nodes(base + ['device']): - dev_path = base + ['device', device] - # remove "system console device <device> modem" (T2570) - if config.exists(dev_path + ['modem']): - config.delete(dev_path + ['modem']) + if config.exists(base + ['device']): + for device in config.list_nodes(base + ['device']): + dev_path = base + ['device', device] + # remove "system console device <device> modem" (T2570) + if config.exists(dev_path + ['modem']): + config.delete(dev_path + ['modem']) - # Only continue on USB based serial consoles - if not 'ttyUSB' in device: - continue + # Only continue on USB based serial consoles + if not 'ttyUSB' in device: + continue - # A serial console has been configured but it does no longer - # exist on the system - cleanup - if not os.path.exists(f'/dev/{device}'): - config.delete(dev_path) - continue + # A serial console has been configured but it does no longer + # exist on the system - cleanup + if not os.path.exists(f'/dev/{device}'): + config.delete(dev_path) + continue - # migrate from ttyUSB device to new device in /dev/serial/by-bus - for root, dirs, files in os.walk('/dev/serial/by-bus'): - for usb_device in files: - device_file = os.path.realpath(os.path.join(root, usb_device)) - # migrate to new USB device names (T2529) - if os.path.basename(device_file) == device: - config.copy(dev_path, base + ['device', usb_device]) - # Delete old USB node from config - config.delete(dev_path) + # migrate from ttyUSB device to new device in /dev/serial/by-bus + for root, dirs, files in os.walk('/dev/serial/by-bus'): + for usb_device in files: + device_file = os.path.realpath(os.path.join(root, usb_device)) + # migrate to new USB device names (T2529) + if os.path.basename(device_file) == device: + config.copy(dev_path, base + ['device', usb_device]) + # Delete old USB node from config + config.delete(dev_path) try: with open(file_name, 'w') as f: diff --git a/src/op_mode/show_interfaces.py b/src/op_mode/show_interfaces.py index 2f0f8a1c9..46571c0c0 100755 --- a/src/op_mode/show_interfaces.py +++ b/src/op_mode/show_interfaces.py @@ -55,7 +55,6 @@ def filtered_interfaces(ifnames, iftypes, vif, vrrp): return an instance of the interface class """ allnames = Section.interfaces() - allnames.sort() vrrp_interfaces = VRRP.active_interfaces() if vrrp else [] @@ -97,10 +96,14 @@ def split_text(text, used=0): line = '' for word in text.split(): - if len(line) + len(word) >= desc_len: - yield f'{line} {word}'[1:] - line = '' - line = f'{line} {word}' + if len(line) + len(word) < desc_len: + line = f'{line} {word}' + continue + if line: + yield line[1:] + else: + line = f'{line} {word}' + yield line[1:] diff --git a/src/systemd/dhcp6c@.service b/src/systemd/dhcp6c@.service index e110eccc1..9a97ee261 100644 --- a/src/systemd/dhcp6c@.service +++ b/src/systemd/dhcp6c@.service @@ -3,15 +3,14 @@ Description=WIDE DHCPv6 client on %i Documentation=man:dhcp6c(8) man:dhcp6c.conf(5) ConditionPathExists=/run/dhcp6c/dhcp6c.%i.conf After=vyos-router.service +StartLimitIntervalSec=0 [Service] WorkingDirectory=/run/dhcp6c Type=forking PIDFile=/run/dhcp6c/dhcp6c.%i.pid ExecStart=/usr/sbin/dhcp6c -D -k /run/dhcp6c/dhcp6c.%i.sock -c /run/dhcp6c/dhcp6c.%i.conf -p /run/dhcp6c/dhcp6c.%i.pid %i - Restart=on-failure -StartLimitIntervalSec=0 RestartSec=20 [Install] diff --git a/src/systemd/dropbear@.service b/src/systemd/dropbear@.service new file mode 100644 index 000000000..606a7ea6d --- /dev/null +++ b/src/systemd/dropbear@.service @@ -0,0 +1,14 @@ +[Unit] +Description=Dropbear SSH per-connection server +Requires=dropbearkey.service +Wants=conserver-server.service +ConditionPathExists=/run/conserver/conserver.cf +After=dropbearkey.service vyos-router.service conserver-server.service + +[Service] +Type=forking +ExecStartPre=/usr/bin/bash -c '/usr/bin/systemctl set-environment PORT=$(cli-shell-api returnActiveValue service console-server device "%I" ssh port)' +ExecStart=-/usr/sbin/dropbear -w -j -k -r /etc/dropbear/dropbear_rsa_host_key -c "/usr/bin/console %I" -P /run/conserver/dropbear.%I.pid -p ${PORT} +PIDFile=/run/conserver/dropbear.%I.pid +KillMode=process +Restart=on-failure diff --git a/src/systemd/dropbearkey.service b/src/systemd/dropbearkey.service new file mode 100644 index 000000000..770641c8b --- /dev/null +++ b/src/systemd/dropbearkey.service @@ -0,0 +1,11 @@ +[Unit] +Description=Dropbear SSH Key Generation +ConditionPathExists=|!/etc/dropbear/dropbear_rsa_host_key + +[Service] +ExecStart=/usr/bin/dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/src/tests/test_util.py b/src/tests/test_util.py new file mode 100644 index 000000000..0e56a67a8 --- /dev/null +++ b/src/tests/test_util.py @@ -0,0 +1,34 @@ +#!/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 unittest +from unittest import TestCase + +import vyos.util + + +class TestVyOSUtil(TestCase): + def setUp(self): + pass + + def test_key_mangline(self): + data = {"foo-bar": {"baz-quux": None}} + expected_data = {"foo_bar": {"baz_quux": None}} + new_data = vyos.util.mangle_dict_keys(data, '-', '_') + self.assertEqual(new_data, expected_data) + diff --git a/src/validators/wireless-phy b/src/validators/wireless-phy new file mode 100755 index 000000000..513a902de --- /dev/null +++ b/src/validators/wireless-phy @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 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 +# 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/>. + +if [ ! -d /sys/class/ieee80211 ]; then + echo No IEEE 802.11 physical interfaces detected + exit 1 +fi + +if [ ! -e /sys/class/ieee80211/$1 ]; then + echo Device interface "$1" does not exist + exit 1 +fi |