diff options
-rw-r--r-- | data/templates/frr/bgpd.frr.tmpl | 3 | ||||
-rw-r--r-- | data/templates/ocserv/ocserv_otp_usr.tmpl | 2 | ||||
-rw-r--r-- | interface-definitions/include/auth-local-users.xml.i | 19 | ||||
-rw-r--r-- | interface-definitions/include/bgp/protocol-common-config.xml.i | 6 | ||||
-rw-r--r-- | interface-definitions/vpn_openconnect.xml.in | 4 | ||||
-rw-r--r-- | op-mode-definitions/show-log.xml.in | 73 | ||||
-rwxr-xr-x | python/vyos/ifconfig/interface.py | 16 | ||||
-rw-r--r-- | python/vyos/ifconfig/loopback.py | 13 | ||||
-rw-r--r-- | python/vyos/util.py | 4 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_protocols_bgp.py | 2 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_system_ipv6.py | 31 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_vpn_openconnect.py | 5 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_vrf.py | 54 | ||||
-rwxr-xr-x | src/conf_mode/vpn_openconnect.py | 30 | ||||
-rwxr-xr-x | src/conf_mode/vrf.py | 8 | ||||
-rwxr-xr-x | src/migration-scripts/openconnect/1-to-2 | 14 | ||||
-rw-r--r-- | src/tests/test_util.py | 15 |
17 files changed, 246 insertions, 53 deletions
diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 45e0544b7..0bc0fd36e 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -545,6 +545,9 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% if parameters.no_fast_external_failover is defined %} no bgp fast-external-failover {% endif %} +{% if parameters.no_suppress_duplicates is defined %} + no bgp suppress-duplicates +{% endif %} {% if parameters.reject_as_sets is defined %} bgp reject-as-sets {% endif %} diff --git a/data/templates/ocserv/ocserv_otp_usr.tmpl b/data/templates/ocserv/ocserv_otp_usr.tmpl index db8893ae8..fea9af5d5 100644 --- a/data/templates/ocserv/ocserv_otp_usr.tmpl +++ b/data/templates/ocserv/ocserv_otp_usr.tmpl @@ -1,6 +1,6 @@ #<token_type> <username> <pin> <secret_hex_key> <counter> <lastpass> <time> {% if username is defined %} -{% for user, user_config in username.itmes() %} +{% for user, user_config in username.items() %} {% if user_config.disable is not defined and user_config.otp is defined and user_config.otp is not none %} {{ user_config.otp.token_tmpl }} {{ user }} {{ user_config.otp.pin | default("-", true) }} {{ user_config.otp.key }} {% endif %} diff --git a/interface-definitions/include/auth-local-users.xml.i b/interface-definitions/include/auth-local-users.xml.i index add2fc8e1..cb456eecf 100644 --- a/interface-definitions/include/auth-local-users.xml.i +++ b/interface-definitions/include/auth-local-users.xml.i @@ -34,45 +34,47 @@ <constraint> <regex>[a-fA-F0-9]{20,10000}</regex> </constraint> - <constraintErrorMessage>Key name must in hex be alphanumerical only (min. 20 hex characters)</constraintErrorMessage> + <constraintErrorMessage>Key name must only include hex characters and be at least 20 characters long</constraintErrorMessage> </properties> </leafNode> <leafNode name="otp-length"> <properties> - <help>Optional. Number of digits in OTP code (default: 6)</help> + <help>Number of digits in OTP code</help> <valueHelp> <format>u32:6-8</format> - <description>Number of digits in OTP code (default: 6)</description> + <description>Number of digits in OTP code</description> </valueHelp> <constraint> <validator name="numeric" argument="--range 6-8"/> </constraint> <constraintErrorMessage>Number of digits in OTP code must be between 6 and 8</constraintErrorMessage> </properties> + <defaultValue>6</defaultValue> </leafNode> <leafNode name="interval"> <properties> - <help>Optional. Time tokens interval in seconds (for time tokens) (default: 30)</help> + <help>Time tokens interval in seconds</help> <valueHelp> <format>u32:5-86400</format> - <description>Time tokens interval in seconds (for time tokens). (default: 30)</description> + <description>Time tokens interval in seconds.</description> </valueHelp> <constraint> <validator name="numeric" argument="--range 5-86400"/> </constraint> <constraintErrorMessage>Time token interval must be between 5 and 86400 seconds</constraintErrorMessage> </properties> + <defaultValue>30</defaultValue> </leafNode> <leafNode name="token-type"> <properties> - <help>Optional. Token type (default: hotp-time)</help> + <help>Token type</help> <valueHelp> <format>hotp-time</format> - <description>time-based OTP algorithm</description> + <description>Time-based OTP algorithm</description> </valueHelp> <valueHelp> <format>hotp-event</format> - <description>event-based OTP algorithm</description> + <description>Event-based OTP algorithm</description> </valueHelp> <constraint> <regex>(hotp-time|hotp-event)</regex> @@ -81,6 +83,7 @@ <list>hotp-time hotp-event</list> </completionHelp> </properties> + <defaultValue>hotp-time</defaultValue> </leafNode> </children> </node> diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 38337b032..b59ff0287 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -1430,6 +1430,12 @@ <valueless/> </properties> </leafNode> + <leafNode name="no-suppress-duplicates"> + <properties> + <help>Disable suppress duplicate updates if the route actually not changed</help> + <valueless/> + </properties> + </leafNode> <leafNode name="reject-as-sets"> <properties> <help>Reject routes with AS_SET or AS_CONFED_SET flag</help> diff --git a/interface-definitions/vpn_openconnect.xml.in b/interface-definitions/vpn_openconnect.xml.in index 631c3b739..05458ed34 100644 --- a/interface-definitions/vpn_openconnect.xml.in +++ b/interface-definitions/vpn_openconnect.xml.in @@ -23,7 +23,7 @@ <help>Use local username/password configuration (OTP supported)</help> <valueHelp> <format>password</format> - <description>Password-only local authentication (default)</description> + <description>Password-only local authentication</description> </valueHelp> <valueHelp> <format>otp</format> @@ -36,7 +36,7 @@ <constraint> <regex>^(password|otp|password-otp)$</regex> </constraint> - <constraintErrorMessage>Invalid authentication mode</constraintErrorMessage> + <constraintErrorMessage>Invalid authentication mode. Must be one of: password, otp or password-otp </constraintErrorMessage> <completionHelp> <list>otp password password-otp</list> </completionHelp> diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index 4c0a7913b..2d75f119d 100644 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -212,6 +212,79 @@ </tagNode> </children> </node> + <node name="protocol"> + <properties> + <help>Show log for Routing Protocols</help> + </properties> + <children> + <leafNode name="ospf"> + <properties> + <help>Show log for OSPF</help> + </properties> + <command>journalctl -b /usr/lib/frr/ospfd</command> + </leafNode> + <leafNode name="ospfv3"> + <properties> + <help>Show log for OSPF for IPv6</help> + </properties> + <command>journalctl -b /usr/lib/frr/ospf6d</command> + </leafNode> + <leafNode name="bgp"> + <properties> + <help>Show log for BGP</help> + </properties> + <command>journalctl -b /usr/lib/frr/bgpd</command> + </leafNode> + <leafNode name="rip"> + <properties> + <help>Show log for RIP</help> + </properties> + <command>journalctl -b /usr/lib/frr/ripd</command> + </leafNode> + <leafNode name="ripng"> + <properties> + <help>Show log for RIPng</help> + </properties> + <command>journalctl -b /usr/lib/frr/ripngd</command> + </leafNode> + <leafNode name="static"> + <properties> + <help>Show log for static route</help> + </properties> + <command>journalctl -b /usr/lib/frr/staticd</command> + </leafNode> + <leafNode name="multicast"> + <properties> + <help>Show log for Multicast protocol</help> + </properties> + <command>journalctl -b /usr/lib/frr/pimd</command> + </leafNode> + <leafNode name="isis"> + <properties> + <help>Show log for ISIS</help> + </properties> + <command>journalctl -b /usr/lib/frr/isisd</command> + </leafNode> + <leafNode name="nhrp"> + <properties> + <help>Show log for NHRP</help> + </properties> + <command>journalctl -b /usr/lib/frr/nhrpd</command> + </leafNode> + <leafNode name="bfd"> + <properties> + <help>Show log for BFD</help> + </properties> + <command>journalctl -b /usr/lib/frr/bfdd</command> + </leafNode> + <leafNode name="mpls"> + <properties> + <help>Show log for MPLS</help> + </properties> + <command>journalctl -b /usr/lib/frr/ldpd</command> + </leafNode> + </children> + </node> <leafNode name="snmp"> <properties> <help>Show log for Simple Network Monitoring Protocol (SNMP)</help> diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 4fda1c0a9..f39da90e4 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -39,7 +39,7 @@ from vyos.util import read_file from vyos.util import get_interface_config from vyos.util import get_interface_namespace from vyos.util import is_systemd_service_active -from vyos.util import sysctl_read +from vyos.util import is_ipv6_enabled from vyos.template import is_ipv4 from vyos.template import is_ipv6 from vyos.validate import is_intf_addr_assigned @@ -1083,6 +1083,10 @@ class Interface(Control): addr_is_v4 = is_ipv4(addr) + # Failsave - do not add IPv6 address if IPv6 is disabled + if is_ipv6(addr) and not is_ipv6_enabled(): + return False + # add to interface if addr == 'dhcp': self.set_dhcp(True) @@ -1498,7 +1502,7 @@ class Interface(Control): self.set_ipv4_source_validation(value) # Only change IPv6 parameters if IPv6 was not explicitly disabled - if sysctl_read('net.ipv6.conf.all.disable_ipv6') == '0': + if is_ipv6_enabled(): # Configure MSS value for IPv6 TCP connections tmp = dict_search('ipv6.adjust_mss', config) value = tmp if (tmp != None) else '0' @@ -1526,10 +1530,6 @@ class Interface(Control): value = tmp if (tmp != None) else '1' self.set_ipv6_dad_messages(value) - # MTU - Maximum Transfer Unit - if 'mtu' in config: - self.set_mtu(config.get('mtu')) - # Delete old IPv6 EUI64 addresses before changing MAC for addr in (dict_search('ipv6.address.eui64_old', config) or []): self.del_ipv6_eui64_address(addr) @@ -1546,6 +1546,10 @@ class Interface(Control): for addr in tmp: self.add_ipv6_eui64_address(addr) + # MTU - Maximum Transfer Unit + if 'mtu' in config: + self.set_mtu(config.get('mtu')) + # re-add ourselves to any bridge we might have fallen out of if 'is_bridge_member' in config: bridge_dict = config.get('is_bridge_member') diff --git a/python/vyos/ifconfig/loopback.py b/python/vyos/ifconfig/loopback.py index de554ef44..30c890fdf 100644 --- a/python/vyos/ifconfig/loopback.py +++ b/python/vyos/ifconfig/loopback.py @@ -13,9 +13,8 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see <http://www.gnu.org/licenses/>. -import vyos.util - from vyos.ifconfig.interface import Interface +from vyos.util import is_ipv6_enabled @Interface.register class LoopbackIf(Interface): @@ -34,8 +33,6 @@ class LoopbackIf(Interface): } } - name = 'loopback' - def remove(self): """ Loopback interface can not be deleted from operating system. We can @@ -62,11 +59,11 @@ class LoopbackIf(Interface): on any interface. """ addr = config.get('address', []) - # We must ensure that the loopback addresses are never deleted from the system - addr += ['127.0.0.1/8'] - if (vyos.util.sysctl_read('net.ipv6.conf.all.disable_ipv6') == '0'): - addr += ['::1/128'] + # We must ensure that the loopback addresses are never deleted from the system + addr.append('127.0.0.1/8') + if is_ipv6_enabled(): + addr.append('::1/128') # Update IP address entry in our dictionary config.update({'address' : addr}) diff --git a/python/vyos/util.py b/python/vyos/util.py index f46775490..f3f323c34 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -1019,3 +1019,7 @@ def sysctl_write(name, value): call(f'sysctl -wq {name}={value}') return True return False + +def is_ipv6_enabled() -> bool: + """ Check if IPv6 support on the system is enabled or not """ + return (sysctl_read('net.ipv6.conf.all.disable_ipv6') == '0') diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index d7230baf4..db1587ba7 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -274,6 +274,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['parameters', 'conditional-advertisement', 'timer', cond_adv_timer]) self.cli_set(base_path + ['parameters', 'fast-convergence']) self.cli_set(base_path + ['parameters', 'minimum-holdtime', min_hold_time]) + self.cli_set(base_path + ['parameters', 'no-suppress-duplicates']) self.cli_set(base_path + ['parameters', 'reject-as-sets']) self.cli_set(base_path + ['parameters', 'shutdown']) self.cli_set(base_path + ['parameters', 'suppress-fib-pending']) @@ -305,6 +306,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' bgp shutdown', frrconfig) self.assertIn(f' bgp suppress-fib-pending', frrconfig) self.assertNotIn(f'bgp ebgp-requires-policy', frrconfig) + self.assertIn(f' no bgp suppress-duplicates', frrconfig) afiv4_config = self.getFRRconfig(' address-family ipv4 unicast') self.assertIn(f' maximum-paths {max_path_v4}', afiv4_config) diff --git a/smoketest/scripts/cli/test_system_ipv6.py b/smoketest/scripts/cli/test_system_ipv6.py index 3112d2e46..837d1dc12 100755 --- a/smoketest/scripts/cli/test_system_ipv6.py +++ b/smoketest/scripts/cli/test_system_ipv6.py @@ -17,7 +17,12 @@ import unittest from base_vyostest_shim import VyOSUnitTestSHIM + +from vyos.template import is_ipv4 from vyos.util import read_file +from vyos.util import is_ipv6_enabled +from vyos.util import get_interface_config +from vyos.validate import is_intf_addr_assigned base_path = ['system', 'ipv6'] @@ -42,6 +47,14 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase): self.assertEqual(read_file(file_forwarding), '0') def test_system_ipv6_disable(self): + # Verify previous "enable" state + self.assertEqual(read_file(file_disable), '0') + self.assertTrue(is_ipv6_enabled()) + + loopbacks = ['127.0.0.1', '::1'] + for addr in loopbacks: + self.assertTrue(is_intf_addr_assigned('lo', addr)) + # Do not assign any IPv6 address on interfaces, this requires a reboot # which can not be tested, but we can read the config file :) self.cli_set(base_path + ['disable']) @@ -49,6 +62,24 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase): # Verify configuration file self.assertEqual(read_file(file_disable), '1') + self.assertFalse(is_ipv6_enabled()) + + for addr in loopbacks: + if is_ipv4(addr): + self.assertTrue(is_intf_addr_assigned('lo', addr)) + else: + self.assertFalse(is_intf_addr_assigned('lo', addr)) + + # T4330: Verify MTU can be changed with IPv6 disabled + mtu = '1600' + eth_if = 'eth0' + self.cli_set(['interfaces', 'ethernet', eth_if, 'mtu', mtu]) + self.cli_commit() + + tmp = get_interface_config(eth_if) + self.assertEqual(tmp['mtu'], int(mtu)) + + self.cli_delete(['interfaces', 'ethernet', eth_if, 'mtu']) def test_system_ipv6_strict_dad(self): # This defaults to 1 diff --git a/smoketest/scripts/cli/test_vpn_openconnect.py b/smoketest/scripts/cli/test_vpn_openconnect.py index b0e859b5c..1f2c36f0d 100755 --- a/smoketest/scripts/cli/test_vpn_openconnect.py +++ b/smoketest/scripts/cli/test_vpn_openconnect.py @@ -37,6 +37,8 @@ class TestVpnOpenconnect(VyOSUnitTestSHIM.TestCase): def test_vpn(self): user = 'vyos_user' password = 'vyos_pass' + otp = '37500000026900000000200000000000' + self.cli_delete(pki_path) self.cli_delete(base_path) @@ -45,7 +47,8 @@ class TestVpnOpenconnect(VyOSUnitTestSHIM.TestCase): self.cli_set(pki_path + ['certificate', 'openconnect', 'private', 'key', key_data]) self.cli_set(base_path + ["authentication", "local-users", "username", user, "password", password]) - self.cli_set(base_path + ["authentication", "mode", "local"]) + self.cli_set(base_path + ["authentication", "local-users", "username", user, "otp", "key", otp]) + self.cli_set(base_path + ["authentication", "mode", "local", "password-otp"]) self.cli_set(base_path + ["network-settings", "client-ip-settings", "subnet", "192.0.2.0/24"]) self.cli_set(base_path + ["ssl", "ca-certificate", 'openconnect']) self.cli_set(base_path + ["ssl", "certificate", 'openconnect']) diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py index 5ffa9c086..5daea589c 100755 --- a/smoketest/scripts/cli/test_vrf.py +++ b/smoketest/scripts/cli/test_vrf.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020-2021 VyOS maintainers and contributors +# Copyright (C) 2020-2022 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 @@ -25,9 +25,10 @@ from base_vyostest_shim import VyOSUnitTestSHIM from vyos.configsession import ConfigSessionError from vyos.ifconfig import Interface from vyos.ifconfig import Section -from vyos.template import is_ipv6 +from vyos.template import is_ipv4 from vyos.util import cmd from vyos.util import read_file +from vyos.util import get_interface_config from vyos.validate import is_intf_addr_assigned base_path = ['vrf'] @@ -105,10 +106,13 @@ class VRFTest(VyOSUnitTestSHIM.TestCase): frrconfig = self.getFRRconfig(f'vrf {vrf}') self.assertIn(f' vni {table}', frrconfig) + tmp = get_interface_config(vrf) + self.assertEqual(int(table), tmp['linkinfo']['info_data']['table']) + # Increment table ID for the next run table = str(int(table) + 1) - def test_vrf_loopback_ips(self): + def test_vrf_loopbacks_ips(self): table = '2000' for vrf in vrfs: base = base_path + ['name', vrf] @@ -119,10 +123,48 @@ class VRFTest(VyOSUnitTestSHIM.TestCase): self.cli_commit() # Verify VRF configuration + loopbacks = ['127.0.0.1', '::1'] for vrf in vrfs: - self.assertTrue(vrf in interfaces()) - self.assertTrue(is_intf_addr_assigned(vrf, '127.0.0.1')) - self.assertTrue(is_intf_addr_assigned(vrf, '::1')) + # Ensure VRF was created + self.assertIn(vrf, interfaces()) + # Test for proper loopback IP assignment + for addr in loopbacks: + self.assertTrue(is_intf_addr_assigned(vrf, addr)) + + def test_vrf_loopbacks_no_ipv6(self): + table = '2002' + for vrf in vrfs: + base = base_path + ['name', vrf] + self.cli_set(base + ['table', str(table)]) + table = str(int(table) + 1) + + # Globally disable IPv6 - this will remove all IPv6 interface addresses + self.cli_set(['system', 'ipv6', 'disable']) + + # commit changes + self.cli_commit() + + # Verify VRF configuration + table = '2002' + loopbacks = ['127.0.0.1', '::1'] + for vrf in vrfs: + # Ensure VRF was created + self.assertIn(vrf, interfaces()) + + # Verify VRF table ID + tmp = get_interface_config(vrf) + self.assertEqual(int(table), tmp['linkinfo']['info_data']['table']) + + # Test for proper loopback IP assignment + for addr in loopbacks: + if is_ipv4(addr): + self.assertTrue(is_intf_addr_assigned(vrf, addr)) + else: + self.assertFalse(is_intf_addr_assigned(vrf, addr)) + + table = str(int(table) + 1) + + self.cli_delete(['system', 'ipv6']) def test_vrf_bind_all(self): table = '2000' diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py index 8e100d9f9..84d31f9a5 100755 --- a/src/conf_mode/vpn_openconnect.py +++ b/src/conf_mode/vpn_openconnect.py @@ -24,6 +24,7 @@ from vyos.pki import wrap_private_key from vyos.template import render from vyos.util import call from vyos.util import is_systemd_service_running +from vyos.util import dict_search from vyos.xml import defaults from vyos import ConfigError from crypt import crypt, mksalt, METHOD_SHA512 @@ -55,6 +56,16 @@ def get_config(): default_values = defaults(base) ocserv = dict_merge(default_values, ocserv) + # workaround a "know limitation" - https://phabricator.vyos.net/T2665 + del ocserv['authentication']['local_users']['username']['otp'] + if not ocserv["authentication"]["local_users"]["username"]: + raise ConfigError('openconnect mode local required at least one user') + default_ocserv_usr_values = default_values['authentication']['local_users']['username']['otp'] + for user, params in ocserv['authentication']['local_users']['username'].items(): + # Not every configuration requires OTP settings + if ocserv['authentication']['local_users']['username'][user].get('otp'): + ocserv['authentication']['local_users']['username'][user]['otp'] = dict_merge(default_ocserv_usr_values, ocserv['authentication']['local_users']['username'][user]['otp']) + if ocserv: ocserv['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True) @@ -69,19 +80,18 @@ def verify(ocserv): if "mode" in ocserv["authentication"]: if "local" in ocserv["authentication"]["mode"]: if "radius" in ocserv["authentication"]["mode"]: - raise ConfigError('openconnect supports only one authentication mode. Currently configured \'local\' and \'radius\' modes') + raise ConfigError('OpenConnect authentication modes are mutually-exclusive, remove either local or radius from your configuration') if not ocserv["authentication"]["local_users"]: - raise ConfigError('openconnect mode local required at leat one user') + raise ConfigError('openconnect mode local required at least one user') if not ocserv["authentication"]["local_users"]["username"]: - raise ConfigError('openconnect mode local required at leat one user') + raise ConfigError('openconnect mode local required at least one user') else: # For OTP mode: verify that each local user has an OTP key if "otp" in ocserv["authentication"]["mode"]["local"]: users_wo_key = [] - for user in ocserv["authentication"]["local_users"]["username"]: - if not ocserv["authentication"]["local_users"]["username"][user].get("otp"): - users_wo_key.append(user) - elif not ocserv["authentication"]["local_users"]["username"][user]["otp"].get("key"): + for user, user_config in ocserv["authentication"]["local_users"]["username"].items(): + # User has no OTP key defined + if dict_search('otp.key', user_config) == None: users_wo_key.append(user) if users_wo_key: raise ConfigError(f'OTP enabled, but no OTP key is configured for these users:\n{users_wo_key}') @@ -156,9 +166,9 @@ def generate(ocserv): if "local_users" in ocserv["authentication"]: for user in ocserv["authentication"]["local_users"]["username"]: # OTP token type from CLI parameters: - otp_interval = ocserv["authentication"]["local_users"]["username"][user]["otp"].get("interval", "30") - token_type = ocserv["authentication"]["local_users"]["username"][user]["otp"].get("token-type", "hotp-time") - otp_length = ocserv["authentication"]["local_users"]["username"][user]["otp"].get("otp-length", "6") + otp_interval = str(ocserv["authentication"]["local_users"]["username"][user]["otp"].get("interval")) + token_type = ocserv["authentication"]["local_users"]["username"][user]["otp"].get("token_type") + otp_length = str(ocserv["authentication"]["local_users"]["username"][user]["otp"].get("otp_length")) if token_type == "hotp-time": otp_type = "HOTP/T" + otp_interval elif token_type == "hotp-event": diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py index 6a521a0dd..c3e2d8efd 100755 --- a/src/conf_mode/vrf.py +++ b/src/conf_mode/vrf.py @@ -30,6 +30,7 @@ from vyos.util import get_interface_config from vyos.util import popen from vyos.util import run from vyos.util import sysctl_write +from vyos.util import is_ipv6_enabled from vyos import ConfigError from vyos import frr from vyos import airbag @@ -215,10 +216,11 @@ def apply(vrf): # set VRF description for e.g. SNMP monitoring vrf_if = Interface(name) - # We also should add proper loopback IP addresses to the newly - # created VRFs for services bound to the loopback address (SNMP, NTP) + # We also should add proper loopback IP addresses to the newly added + # VRF for services bound to the loopback address (SNMP, NTP) vrf_if.add_addr('127.0.0.1/8') - vrf_if.add_addr('::1/128') + if is_ipv6_enabled(): + vrf_if.add_addr('::1/128') # add VRF description if available vrf_if.set_alias(config.get('description', '')) diff --git a/src/migration-scripts/openconnect/1-to-2 b/src/migration-scripts/openconnect/1-to-2 index 36d807a3c..7031fb252 100755 --- a/src/migration-scripts/openconnect/1-to-2 +++ b/src/migration-scripts/openconnect/1-to-2 @@ -37,15 +37,15 @@ if not config.exists(cfg_base): # Nothing to do sys.exit(0) else: - if config.exists(cfg_base + ['authentication'] + ['mode']): - if config.return_value(cfg_base + ['authentication'] + ['mode']) == 'radius': + if config.exists(cfg_base + ['authentication', 'mode']): + if config.return_value(cfg_base + ['authentication', 'mode']) == 'radius': # if "mode value radius", change to "tag node mode + valueless node radius" - config.delete(cfg_base + ['authentication'] + ['mode'] + ['radius']) - config.set(cfg_base + ['authentication'] + ['mode'] + ['radius'], value=None, replace=True) - elif not config.exists(cfg_base + ['authentication'] + ['mode'] + ['local']): + config.delete(cfg_base + ['authentication','mode', 'radius']) + config.set(cfg_base + ['authentication', 'mode', 'radius'], value=None, replace=True) + elif not config.exists(cfg_base + ['authentication', 'mode', 'local']): # if "mode local", change to "tag node mode + node local value password" - config.delete(cfg_base + ['authentication'] + ['mode'] + ['local']) - config.set(cfg_base + ['authentication'] + ['mode'] + ['local'], value='password', replace=True) + config.delete(cfg_base + ['authentication', 'mode', 'local']) + config.set(cfg_base + ['authentication', 'mode', 'local'], value='password', replace=True) try: with open(file_name, 'w') as f: f.write(config.to_string()) diff --git a/src/tests/test_util.py b/src/tests/test_util.py index 9bd27adc0..91890262c 100644 --- a/src/tests/test_util.py +++ b/src/tests/test_util.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020-2021 VyOS maintainers and contributors +# Copyright (C) 2020-2022 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 @@ -23,3 +23,16 @@ class TestVyOSUtil(TestCase): expected_data = {"foo_bar": {"baz_quux": None}} new_data = mangle_dict_keys(data, '-', '_') self.assertEqual(new_data, expected_data) + + def test_sysctl_read(self): + self.assertEqual(sysctl_read('net.ipv4.conf.lo.forwarding'), '1') + + def test_ipv6_enabled(self): + tmp = sysctl_read('net.ipv6.conf.all.disable_ipv6') + # We need to test for both variants as this depends on how the + # Docker container is started (with or without IPv6 support) - so we + # will simply check both cases to not make the users life miserable. + if tmp == '0': + self.assertTrue(is_ipv6_enabled()) + else: + self.assertFalse(is_ipv6_enabled()) |