diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/host_name.py | 5 | ||||
-rwxr-xr-x | src/conf_mode/nat.py | 23 | ||||
-rwxr-xr-x | src/conf_mode/nat66.py | 8 | ||||
-rwxr-xr-x | src/conf_mode/system-login.py | 6 | ||||
-rwxr-xr-x | src/migration-scripts/l2tp/4-to-5 | 20 | ||||
-rwxr-xr-x | src/migration-scripts/pppoe-server/6-to-7 | 21 | ||||
-rwxr-xr-x | src/migration-scripts/sstp/4-to-5 | 19 | ||||
-rwxr-xr-x | src/migration-scripts/system/26-to-27 | 47 | ||||
-rw-r--r-- | src/tests/test_jinja_filters.py | 69 | ||||
-rw-r--r-- | src/tests/test_template.py | 44 |
10 files changed, 142 insertions, 120 deletions
diff --git a/src/conf_mode/host_name.py b/src/conf_mode/host_name.py index 36d1f6493..6204cf247 100755 --- a/src/conf_mode/host_name.py +++ b/src/conf_mode/host_name.py @@ -61,8 +61,9 @@ def get_config(config=None): hosts['domain_name'] = conf.return_value(['system', 'domain-name']) hosts['domain_search'].append(hosts['domain_name']) - for search in conf.return_values(['system', 'domain-search', 'domain']): - hosts['domain_search'].append(search) + if conf.exists(['system', 'domain-search']): + for search in conf.return_values(['system', 'domain-search']): + hosts['domain_search'].append(search) if conf.exists(['system', 'name-server']): for ns in conf.return_values(['system', 'name-server']): diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py index 44b13d413..20570da62 100755 --- a/src/conf_mode/nat.py +++ b/src/conf_mode/nat.py @@ -80,15 +80,13 @@ def verify_rule(config, err_msg, groups_dict): dict_search('source.port', config)): if config['protocol'] not in ['tcp', 'udp', 'tcp_udp']: - raise ConfigError(f'{err_msg}\n' \ - 'ports can only be specified when protocol is '\ - 'either tcp, udp or tcp_udp!') + raise ConfigError(f'{err_msg} ports can only be specified when '\ + 'protocol is either tcp, udp or tcp_udp!') if is_ip_network(dict_search('translation.address', config)): - raise ConfigError(f'{err_msg}\n' \ - 'Cannot use ports with an IPv4 network as translation address as it\n' \ - 'statically maps a whole network of addresses onto another\n' \ - 'network of addresses') + raise ConfigError(f'{err_msg} cannot use ports with an IPv4 network as '\ + 'translation address as it statically maps a whole network '\ + 'of addresses onto another network of addresses!') for side in ['destination', 'source']: if side in config: @@ -152,10 +150,10 @@ def verify(nat): if 'outbound_interface' in config: if 'name' in config['outbound_interface'] and 'group' in config['outbound_interface']: - raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for nat source rule "{rule}"') + raise ConfigError(f'{err_msg} cannot specify both interface group and interface name for nat source rule "{rule}"') elif 'name' in config['outbound_interface']: if config['outbound_interface']['name'] not in 'any' and config['outbound_interface']['name'] not in interfaces(): - Warning(f'{err_msg} - interface "{config["outbound_interface"]["name"]}" does not exist on this system') + Warning(f'NAT interface "{config["outbound_interface"]["name"]}" for source NAT rule "{rule}" does not exist!') if not dict_search('translation.address', config) and not dict_search('translation.port', config): if 'exclude' not in config and 'backend' not in config['load_balance']: @@ -176,10 +174,10 @@ def verify(nat): if 'inbound_interface' in config: if 'name' in config['inbound_interface'] and 'group' in config['inbound_interface']: - raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for destination nat rule "{rule}"') + raise ConfigError(f'{err_msg} cannot specify both interface group and interface name for destination nat rule "{rule}"') elif 'name' in config['inbound_interface']: if config['inbound_interface']['name'] not in 'any' and config['inbound_interface']['name'] not in interfaces(): - Warning(f'{err_msg} - interface "{config["inbound_interface"]["name"]}" does not exist on this system') + Warning(f'NAT interface "{config["inbound_interface"]["name"]}" for destination NAT rule "{rule}" does not exist!') if not dict_search('translation.address', config) and not dict_search('translation.port', config) and 'redirect' not in config['translation']: if 'exclude' not in config and 'backend' not in config['load_balance']: @@ -193,8 +191,7 @@ def verify(nat): err_msg = f'Static NAT configuration error in rule {rule}:' if 'inbound_interface' not in config: - raise ConfigError(f'{err_msg}\n' \ - 'inbound-interface not specified') + raise ConfigError(f'{err_msg} inbound-interface not specified') # common rule verification verify_rule(config, err_msg, nat['firewall_group']) diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py index dee1551fe..4c1ead258 100755 --- a/src/conf_mode/nat66.py +++ b/src/conf_mode/nat66.py @@ -64,10 +64,10 @@ def verify(nat): if 'outbound_interface' in config: if 'name' in config['outbound_interface'] and 'group' in config['outbound_interface']: - raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for nat source rule "{rule}"') + raise ConfigError(f'{err_msg} cannot specify both interface group and interface name for nat source rule "{rule}"') elif 'name' in config['outbound_interface']: if config['outbound_interface']['name'] not in 'any' and config['outbound_interface']['name'] not in interfaces(): - Warning(f'{err_msg} - interface "{config["outbound_interface"]["name"]}" does not exist on this system') + Warning(f'NAT66 interface "{config["outbound_interface"]["name"]}" for source NAT66 rule "{rule}" does not exist!') addr = dict_search('translation.address', config) if addr != None: @@ -88,10 +88,10 @@ def verify(nat): if 'inbound_interface' in config: if 'name' in config['inbound_interface'] and 'group' in config['inbound_interface']: - raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for destination nat rule "{rule}"') + raise ConfigError(f'{err_msg} cannot specify both interface group and interface name for destination nat rule "{rule}"') elif 'name' in config['inbound_interface']: if config['inbound_interface']['name'] not in 'any' and config['inbound_interface']['name'] not in interfaces(): - Warning(f'{err_msg} - interface "{config["inbound_interface"]["name"]}" does not exist on this system') + Warning(f'NAT66 interface "{config["inbound_interface"]["name"]}" for destination NAT66 rule "{rule}" does not exist!') return None diff --git a/src/conf_mode/system-login.py b/src/conf_mode/system-login.py index aeac82462..f34575aff 100755 --- a/src/conf_mode/system-login.py +++ b/src/conf_mode/system-login.py @@ -29,6 +29,7 @@ from vyos.defaults import directories from vyos.template import render from vyos.template import is_ipv4 from vyos.utils.dict import dict_search +from vyos.utils.file import chown from vyos.utils.process import cmd from vyos.utils.process import call from vyos.utils.process import rc_cmd @@ -334,13 +335,16 @@ def apply(login): command += f' --groups frr,frrvty,vyattacfg,sudo,adm,dip,disk,_kea {user}' try: cmd(command) - # we should not rely on the value stored in # user_config['home_directory'], as a crazy user will choose # username root or any other system user which will fail. # # XXX: Should we deny using root at all? home_dir = getpwnam(user).pw_dir + # T5875: ensure UID is properly set on home directory if user is re-added + if os.path.exists(home_dir): + chown(home_dir, user=user, recursive=True) + render(f'{home_dir}/.ssh/authorized_keys', 'login/authorized_keys.j2', user_config, permission=0o600, formater=lambda _: _.replace(""", '"'), diff --git a/src/migration-scripts/l2tp/4-to-5 b/src/migration-scripts/l2tp/4-to-5 index fe8ab357e..496dc83d6 100755 --- a/src/migration-scripts/l2tp/4-to-5 +++ b/src/migration-scripts/l2tp/4-to-5 @@ -45,12 +45,22 @@ if not config.exists(pool_base): exit(0) default_pool = '' range_pool_name = 'default-range-pool' -subnet_pool_name = 'default-subnet-pool' +subnet_base_name = 'default-subnet-pool' +number = 1 +subnet_pool_name = f'{subnet_base_name}-{number}' +prev_subnet_pool = subnet_pool_name if config.exists(pool_base + ['subnet']): - subnet = config.return_value(pool_base + ['subnet']) - config.delete(pool_base + ['subnet']) - config.set(pool_base + [subnet_pool_name, 'range'], value=subnet) default_pool = subnet_pool_name + for subnet in config.return_values(pool_base + ['subnet']): + config.set(pool_base + [subnet_pool_name, 'range'], value=subnet) + if prev_subnet_pool != subnet_pool_name: + config.set(pool_base + [prev_subnet_pool, 'next-pool'], + value=subnet_pool_name) + prev_subnet_pool = subnet_pool_name + number += 1 + subnet_pool_name = f'{subnet_base_name}-{number}' + + config.delete(pool_base + ['subnet']) if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']): start_ip = config.return_value(pool_base + ['start']) @@ -61,7 +71,7 @@ if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']): config.set(pool_base + [range_pool_name, 'range'], value=ip_range) if default_pool: config.set(pool_base + [range_pool_name, 'next-pool'], - value=subnet_pool_name) + value=default_pool) default_pool = range_pool_name if default_pool: diff --git a/src/migration-scripts/pppoe-server/6-to-7 b/src/migration-scripts/pppoe-server/6-to-7 index 34996d8fe..d856c1f34 100755 --- a/src/migration-scripts/pppoe-server/6-to-7 +++ b/src/migration-scripts/pppoe-server/6-to-7 @@ -50,13 +50,24 @@ if not config.exists(pool_base): exit(0) default_pool = '' range_pool_name = 'default-range-pool' -subnet_pool_name = 'default-subnet-pool' + +subnet_base_name = 'default-subnet-pool' +number = 1 +subnet_pool_name = f'{subnet_base_name}-{number}' +prev_subnet_pool = subnet_pool_name #Default nameless pools migrations if config.exists(pool_base + ['subnet']): - subnet = config.return_value(pool_base + ['subnet']) - config.delete(pool_base + ['subnet']) - config.set(pool_base + [subnet_pool_name, 'range'], value=subnet) default_pool = subnet_pool_name + for subnet in config.return_values(pool_base + ['subnet']): + config.set(pool_base + [subnet_pool_name, 'range'], value=subnet) + if prev_subnet_pool != subnet_pool_name: + config.set(pool_base + [prev_subnet_pool, 'next-pool'], + value=subnet_pool_name) + prev_subnet_pool = subnet_pool_name + number += 1 + subnet_pool_name = f'{subnet_base_name}-{number}' + + config.delete(pool_base + ['subnet']) if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']): start_ip = config.return_value(pool_base + ['start']) @@ -67,7 +78,7 @@ if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']): config.set(pool_base + [range_pool_name, 'range'], value=ip_range) if default_pool: config.set(pool_base + [range_pool_name, 'next-pool'], - value=subnet_pool_name) + value=default_pool) default_pool = range_pool_name gateway = '' diff --git a/src/migration-scripts/sstp/4-to-5 b/src/migration-scripts/sstp/4-to-5 index 0f332e04f..3a86c79ec 100755 --- a/src/migration-scripts/sstp/4-to-5 +++ b/src/migration-scripts/sstp/4-to-5 @@ -43,12 +43,23 @@ if not config.exists(base): if not config.exists(pool_base): exit(0) -subnet_pool_name = 'default-subnet-pool' +subnet_base_name = 'default-subnet-pool' +number = 1 +subnet_pool_name = f'{subnet_base_name}-{number}' +prev_subnet_pool = subnet_pool_name if config.exists(pool_base + ['subnet']): - subnet = config.return_value(pool_base + ['subnet']) + default_pool = subnet_pool_name + for subnet in config.return_values(pool_base + ['subnet']): + config.set(pool_base + [subnet_pool_name, 'range'], value=subnet) + if prev_subnet_pool != subnet_pool_name: + config.set(pool_base + [prev_subnet_pool, 'next-pool'], + value=subnet_pool_name) + prev_subnet_pool = subnet_pool_name + number += 1 + subnet_pool_name = f'{subnet_base_name}-{number}' + config.delete(pool_base + ['subnet']) - config.set(pool_base + [subnet_pool_name, 'range'], value=subnet) - config.set(base + ['default-pool'], value=subnet_pool_name) + config.set(base + ['default-pool'], value=default_pool) # format as tag node config.set_tag(pool_base) diff --git a/src/migration-scripts/system/26-to-27 b/src/migration-scripts/system/26-to-27 new file mode 100755 index 000000000..80bb82cbd --- /dev/null +++ b/src/migration-scripts/system/26-to-27 @@ -0,0 +1,47 @@ +#!/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/>. +# +# T5877: migrate 'system domain-search domain' to 'system domain-search' + +from sys import exit, argv +from vyos.configtree import ConfigTree + +if len(argv) < 2: + print("Must specify file name!") + exit(1) + +file_name = argv[1] +with open(file_name, 'r') as f: + config_file = f.read() + +base = ['system', 'domain-search'] +config = ConfigTree(config_file) + +if not config.exists(base): + exit(0) + +if config.exists(base + ['domain']): + entries = config.return_values(base + ['domain']) + config.delete(base + ['domain']) + for entry in entries: + config.set(base, value=entry, replace=False) + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print(f'Failed to save the modified config: {e}') + exit(1) diff --git a/src/tests/test_jinja_filters.py b/src/tests/test_jinja_filters.py deleted file mode 100644 index 8a7241fe3..000000000 --- a/src/tests/test_jinja_filters.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/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/>. - -from unittest import TestCase - -from ipaddress import ip_network -from vyos.template import address_from_cidr -from vyos.template import netmask_from_cidr -from vyos.template import is_ipv4 -from vyos.template import is_ipv6 -from vyos.template import first_host_address -from vyos.template import last_host_address -from vyos.template import inc_ip - -class TestTeamplteHelpers(TestCase): - def setUp(self): - pass - - def test_helpers_from_cidr(self): - network_v4 = '192.0.2.0/26' - self.assertEqual(address_from_cidr(network_v4), str(ip_network(network_v4).network_address)) - self.assertEqual(netmask_from_cidr(network_v4), str(ip_network(network_v4).netmask)) - - def test_helpers_ipv4(self): - self.assertTrue(is_ipv4('192.0.2.1')) - self.assertTrue(is_ipv4('192.0.2.0/24')) - self.assertTrue(is_ipv4('192.0.2.1/32')) - self.assertTrue(is_ipv4('10.255.1.2')) - self.assertTrue(is_ipv4('10.255.1.0/24')) - self.assertTrue(is_ipv4('10.255.1.2/32')) - self.assertFalse(is_ipv4('2001:db8::')) - self.assertFalse(is_ipv4('2001:db8::1')) - self.assertFalse(is_ipv4('2001:db8::/64')) - - def test_helpers_ipv6(self): - self.assertFalse(is_ipv6('192.0.2.1')) - self.assertFalse(is_ipv6('192.0.2.0/24')) - self.assertFalse(is_ipv6('192.0.2.1/32')) - self.assertFalse(is_ipv6('10.255.1.2')) - self.assertFalse(is_ipv6('10.255.1.0/24')) - self.assertFalse(is_ipv6('10.255.1.2/32')) - self.assertTrue(is_ipv6('2001:db8::')) - self.assertTrue(is_ipv6('2001:db8::1')) - self.assertTrue(is_ipv6('2001:db8::1/64')) - self.assertTrue(is_ipv6('2001:db8::/32')) - self.assertTrue(is_ipv6('2001:db8::/64')) - - def test_helpers_first_host_address(self): - self.assertEqual(first_host_address('10.0.0.0/24'), '10.0.0.1') - self.assertEqual(first_host_address('10.0.0.128/25'), '10.0.0.129') - self.assertEqual(first_host_address('10.0.0.200/29'), '10.0.0.201') - - self.assertEqual(first_host_address('2001:db8::/64'), '2001:db8::') - self.assertEqual(first_host_address('2001:db8::/112'), '2001:db8::') - self.assertEqual(first_host_address('2001:db8::10/112'), '2001:db8::10') - self.assertEqual(first_host_address('2001:db8::100/112'), '2001:db8::100') diff --git a/src/tests/test_template.py b/src/tests/test_template.py index 2d065f545..aba97015e 100644 --- a/src/tests/test_template.py +++ b/src/tests/test_template.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-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,6 +17,7 @@ import os import vyos.template +from ipaddress import ip_network from unittest import TestCase class TestVyOSTemplate(TestCase): @@ -67,6 +68,9 @@ class TestVyOSTemplate(TestCase): # ValueError: 2001:db8::1/48 has host bits set self.assertEqual(vyos.template.address_from_cidr('2001:db8::1/48'), '2001:db8::1') + network_v4 = '192.0.2.0/26' + self.assertEqual(vyos.template.address_from_cidr(network_v4), str(ip_network(network_v4).network_address)) + def test_netmask_from_cidr(self): self.assertEqual(vyos.template.netmask_from_cidr('192.0.2.0/24'), '255.255.255.0') self.assertEqual(vyos.template.netmask_from_cidr('192.0.2.128/25'), '255.255.255.128') @@ -80,28 +84,35 @@ class TestVyOSTemplate(TestCase): # ValueError: 2001:db8:1:/64 has host bits set self.assertEqual(vyos.template.netmask_from_cidr('2001:db8:1:/64'), 'ffff:ffff:ffff:ffff::') + network_v4 = '192.0.2.0/26' + self.assertEqual(vyos.template.netmask_from_cidr(network_v4), str(ip_network(network_v4).netmask)) + def test_first_host_address(self): - self.assertEqual(vyos.template.first_host_address('10.0.0.0/24'), '10.0.0.1') - self.assertEqual(vyos.template.first_host_address('10.0.0.128/25'), '10.0.0.129') - self.assertEqual(vyos.template.first_host_address('2001:db8::/64'), '2001:db8::') + self.assertEqual(vyos.template.first_host_address('10.0.0.0/24'), '10.0.0.1') + self.assertEqual(vyos.template.first_host_address('10.0.0.10/24'), '10.0.0.1') + self.assertEqual(vyos.template.first_host_address('10.0.0.255/24'), '10.0.0.1') + self.assertEqual(vyos.template.first_host_address('10.0.0.128/25'), '10.0.0.129') + self.assertEqual(vyos.template.first_host_address('2001:db8::/64'), '2001:db8::1') + self.assertEqual(vyos.template.first_host_address('2001:db8::1000/64'), '2001:db8::1') + self.assertEqual(vyos.template.first_host_address('2001:db8::ffff:ffff:ffff:ffff/64'), '2001:db8::1') def test_last_host_address(self): - self.assertEqual(vyos.template.last_host_address('10.0.0.0/24'), '10.0.0.254') - self.assertEqual(vyos.template.last_host_address('10.0.0.128/25'), '10.0.0.254') - self.assertEqual(vyos.template.last_host_address('2001:db8::/64'), '2001:db8::ffff:ffff:ffff:ffff') + self.assertEqual(vyos.template.last_host_address('10.0.0.0/24'), '10.0.0.254') + self.assertEqual(vyos.template.last_host_address('10.0.0.128/25'), '10.0.0.254') + self.assertEqual(vyos.template.last_host_address('2001:db8::/64'), '2001:db8::ffff:ffff:ffff:ffff') def test_increment_ip(self): - self.assertEqual(vyos.template.inc_ip('10.0.0.0/24', '2'), '10.0.0.2') - self.assertEqual(vyos.template.inc_ip('10.0.0.0', '2'), '10.0.0.2') - self.assertEqual(vyos.template.inc_ip('10.0.0.0', '10'), '10.0.0.10') - self.assertEqual(vyos.template.inc_ip('2001:db8::/64', '2'), '2001:db8::2') - self.assertEqual(vyos.template.inc_ip('2001:db8::', '10'), '2001:db8::a') + self.assertEqual(vyos.template.inc_ip('10.0.0.0/24', '2'), '10.0.0.2') + self.assertEqual(vyos.template.inc_ip('10.0.0.0', '2'), '10.0.0.2') + self.assertEqual(vyos.template.inc_ip('10.0.0.0', '10'), '10.0.0.10') + self.assertEqual(vyos.template.inc_ip('2001:db8::/64', '2'), '2001:db8::2') + self.assertEqual(vyos.template.inc_ip('2001:db8::', '10'), '2001:db8::a') def test_decrement_ip(self): - self.assertEqual(vyos.template.dec_ip('10.0.0.100/24', '1'), '10.0.0.99') - self.assertEqual(vyos.template.dec_ip('10.0.0.90', '10'), '10.0.0.80') - self.assertEqual(vyos.template.dec_ip('2001:db8::b/64', '10'), '2001:db8::1') - self.assertEqual(vyos.template.dec_ip('2001:db8::f', '5'), '2001:db8::a') + self.assertEqual(vyos.template.dec_ip('10.0.0.100/24', '1'), '10.0.0.99') + self.assertEqual(vyos.template.dec_ip('10.0.0.90', '10'), '10.0.0.80') + self.assertEqual(vyos.template.dec_ip('2001:db8::b/64', '10'), '2001:db8::1') + self.assertEqual(vyos.template.dec_ip('2001:db8::f', '5'), '2001:db8::a') def test_is_network(self): self.assertFalse(vyos.template.is_ip_network('192.0.2.0')) @@ -181,4 +192,3 @@ class TestVyOSTemplate(TestCase): for group_name, group_config in data['ike_group'].items(): ciphers = vyos.template.get_esp_ike_cipher(group_config) self.assertIn(IKEv2_DEFAULT, ','.join(ciphers)) - |