diff --git a/data/config-mode-dependencies/vyos-1x.json b/data/config-mode-dependencies/vyos-1x.json index 4fd94d895..b62603e34 100644 --- a/data/config-mode-dependencies/vyos-1x.json +++ b/data/config-mode-dependencies/vyos-1x.json @@ -1,52 +1,55 @@ { "system_conntrack": { "conntrack_sync": ["service_conntrack-sync"] }, "firewall": { "conntrack": ["system_conntrack"], "group_resync": ["system_conntrack", "nat", "policy_route"] }, "interfaces_bonding": { "ethernet": ["interfaces_ethernet"] }, "interfaces_bridge": { "vxlan": ["interfaces_vxlan"] }, "load_balancing_wan": { "conntrack": ["system_conntrack"] }, "nat": { "conntrack": ["system_conntrack"] }, "nat66": { "conntrack": ["system_conntrack"] }, "pki": { "ethernet": ["interfaces_ethernet"], "openvpn": ["interfaces_openvpn"], "https": ["service_https"], "ipsec": ["vpn_ipsec"], "openconnect": ["vpn_openconnect"], "sstp": ["vpn_sstp"] }, + "vpn_l2tp": { + "ipsec": ["vpn_ipsec"] + }, "qos": { "bonding": ["interfaces_bonding"], "bridge": ["interfaces_bridge"], "dummy": ["interfaces_dummy"], "ethernet": ["interfaces_ethernet"], "geneve": ["interfaces_geneve"], "input": ["interfaces_input"], "l2tpv3": ["interfaces_l2tpv3"], "loopback": ["interfaces_loopback"], "macsec": ["interfaces_macsec"], "openvpn": ["interfaces_openvpn"], "pppoe": ["interfaces_pppoe"], "pseudo-ethernet": ["interfaces_pseudo-ethernet"], "tunnel": ["interfaces_tunnel"], "vti": ["interfaces_vti"], "vxlan": ["interfaces_vxlan"], "wireguard": ["interfaces_wireguard"], "wireless": ["interfaces_wireless"], "wwan": ["interfaces_wwan"] } } diff --git a/smoketest/scripts/cli/test_vpn_l2tp.py b/smoketest/scripts/cli/test_vpn_l2tp.py index 3d9d94f52..e253f0e49 100755 --- a/smoketest/scripts/cli/test_vpn_l2tp.py +++ b/smoketest/scripts/cli/test_vpn_l2tp.py @@ -1,59 +1,100 @@ #!/usr/bin/env python3 # # Copyright (C) 2023-2024 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 import unittest from base_accel_ppp_test import BasicAccelPPPTest from configparser import ConfigParser from vyos.utils.process import cmd class TestVPNL2TPServer(BasicAccelPPPTest.TestCase): @classmethod def setUpClass(cls): cls._base_path = ['vpn', 'l2tp', 'remote-access'] cls._config_file = '/run/accel-pppd/l2tp.conf' cls._chap_secrets = '/run/accel-pppd/l2tp.chap-secrets' cls._protocol_section = 'l2tp' # call base-classes classmethod super(TestVPNL2TPServer, cls).setUpClass() @classmethod def tearDownClass(cls): super(TestVPNL2TPServer, cls).tearDownClass() def basic_protocol_specific_config(self): pass def test_l2tp_server_authentication_protocols(self): # Test configuration of local authentication for PPPoE server self.basic_config() # explicitly test mschap-v2 - no special reason self.set( ['authentication', 'protocols', 'mschap-v2']) # commit changes self.cli_commit() # Validate configuration values conf = ConfigParser(allow_no_value=True) conf.read(self._config_file) self.assertEqual(conf['modules']['auth_mschap_v2'], None) + def test_vpn_l2tp_dependence_ipsec_swanctl(self): + # Test config vpn for tasks T3843 and T5926 + + base_path = ['vpn', 'l2tp', 'remote-access'] + # make precondition + self.cli_set(['interfaces', 'dummy', 'dum0', 'address', '203.0.113.1/32']) + self.cli_set(['vpn', 'ipsec', 'interface', 'dum0']) + + self.cli_commit() + # check ipsec apply to swanctl + self.assertEqual('', cmd('echo vyos | sudo -S swanctl -L ')) + + self.cli_set(base_path + ['authentication', 'local-users', 'username', 'foo', 'password', 'bar']) + self.cli_set(base_path + ['authentication', 'mode', 'local']) + self.cli_set(base_path + ['authentication', 'protocols', 'chap']) + self.cli_set(base_path + ['client-ip-pool', 'first', 'range', '10.200.100.100-10.200.100.110']) + self.cli_set(base_path + ['description', 'VPN - REMOTE']) + self.cli_set(base_path + ['name-server', '1.1.1.1']) + self.cli_set(base_path + ['ipsec-settings', 'authentication', 'mode', 'pre-shared-secret']) + self.cli_set(base_path + ['ipsec-settings', 'authentication', 'pre-shared-secret', 'SeCret']) + self.cli_set(base_path + ['ipsec-settings', 'ike-lifetime', '8600']) + self.cli_set(base_path + ['ipsec-settings', 'lifetime', '3600']) + self.cli_set(base_path + ['outside-address', '203.0.113.1']) + self.cli_set(base_path + ['gateway-address', '203.0.113.1']) + + self.cli_commit() + + # check l2tp apply to swanctl + self.assertTrue('l2tp_remote_access:' in cmd('echo vyos | sudo -S swanctl -L ')) + + self.cli_delete(['vpn', 'l2tp']) + self.cli_commit() + + # check l2tp apply to swanctl after delete config + self.assertEqual('', cmd('echo vyos | sudo -S swanctl -L ')) + + # need to correct tearDown test + self.basic_config() + self.cli_set(base_path + ['authentication', 'protocols', 'chap']) + self.cli_commit() + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/vpn_l2tp.py b/src/conf_mode/vpn_l2tp.py index 36b3d2a30..4ca717814 100755 --- a/src/conf_mode/vpn_l2tp.py +++ b/src/conf_mode/vpn_l2tp.py @@ -1,112 +1,116 @@ #!/usr/bin/env python3 # # Copyright (C) 2019-2024 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.configdep import call_dependents, set_dependents from vyos.configdict import get_accel_dict from vyos.template import render from vyos.utils.process import call from vyos.utils.dict import dict_search from vyos.accel_ppp_util import verify_accel_ppp_base_service from vyos.accel_ppp_util import verify_accel_ppp_ip_pool from vyos.accel_ppp_util import get_pools_in_order from vyos.base import Warning from vyos import ConfigError from vyos import airbag airbag.enable() l2tp_conf = '/run/accel-pppd/l2tp.conf' l2tp_chap_secrets = '/run/accel-pppd/l2tp.chap-secrets' def get_config(config=None): if config: conf = config else: conf = Config() base = ['vpn', 'l2tp', 'remote-access'] + + set_dependents('ipsec', conf) + if not conf.exists(base): return None # retrieve common dictionary keys l2tp = get_accel_dict(conf, base, l2tp_chap_secrets) if dict_search('client_ip_pool', l2tp): # Multiple named pools require ordered values T5099 l2tp['ordered_named_pools'] = get_pools_in_order( dict_search('client_ip_pool', l2tp)) l2tp['server_type'] = 'l2tp' return l2tp def verify(l2tp): if not l2tp: return None verify_accel_ppp_base_service(l2tp) if dict_search('authentication.radius.dynamic_author.server', l2tp): if not dict_search('authentication.radius.dynamic_author.key', l2tp): raise ConfigError('DA/CoE server key required!') verify_accel_ppp_ip_pool(l2tp) if 'wins_server' in l2tp and len(l2tp['wins_server']) > 2: raise ConfigError( 'Not more then two WINS name-servers can be configured') return None def generate(l2tp): if not l2tp: return None render(l2tp_conf, 'accel-ppp/l2tp.config.j2', l2tp) if dict_search('authentication.mode', l2tp) == 'local': render(l2tp_chap_secrets, 'accel-ppp/chap-secrets.config_dict.j2', l2tp, permission=0o640) return None def apply(l2tp): if not l2tp: call('systemctl stop accel-ppp@l2tp.service') for file in [l2tp_chap_secrets, l2tp_conf]: if os.path.exists(file): os.unlink(file) + else: + call('systemctl restart accel-ppp@l2tp.service') - return None - - call('systemctl restart accel-ppp@l2tp.service') + call_dependents() if __name__ == '__main__': try: c = get_config() verify(c) generate(c) apply(c) except ConfigError as e: print(e) exit(1)