From 18ea3673a105d9d12699afb2607c81412dde441b Mon Sep 17 00:00:00 2001 From: Lucas Christian Date: Sun, 11 Aug 2024 23:06:02 -0700 Subject: T6183: interfaces openvpn: suppport specifying IP protocol version --- smoketest/scripts/cli/test_interfaces_openvpn.py | 186 +++++++++++++++++++++++ 1 file changed, 186 insertions(+) (limited to 'smoketest/scripts/cli') diff --git a/smoketest/scripts/cli/test_interfaces_openvpn.py b/smoketest/scripts/cli/test_interfaces_openvpn.py index d8a091aaa..e087b8735 100755 --- a/smoketest/scripts/cli/test_interfaces_openvpn.py +++ b/smoketest/scripts/cli/test_interfaces_openvpn.py @@ -250,6 +250,67 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase): interface = f'vtun{ii}' self.assertNotIn(interface, interfaces()) + def test_openvpn_client_ip_version(self): + # Test the client mode behavior combined with different IP protocol versions + + interface = 'vtun10' + remote_host = '192.0.2.10' + remote_host_v6 = 'fd00::2:10' + path = base_path + [interface] + auth_hash = 'sha1' + + # Default behavior: client uses uspecified protocol version (udp) + self.cli_set(path + ['device-type', 'tun']) + self.cli_set(path + ['encryption', 'data-ciphers', 'aes256']) + self.cli_set(path + ['hash', auth_hash]) + self.cli_set(path + ['mode', 'client']) + self.cli_set(path + ['persistent-tunnel']) + self.cli_set(path + ['protocol', 'udp']) + self.cli_set(path + ['remote-host', remote_host]) + self.cli_set(path + ['remote-port', remote_port]) + self.cli_set(path + ['tls', 'ca-certificate', 'ovpn_test']) + self.cli_set(path + ['tls', 'certificate', 'ovpn_test']) + self.cli_set(path + ['vrf', vrf_name]) + self.cli_set(path + ['authentication', 'username', interface+'user']) + self.cli_set(path + ['authentication', 'password', interface+'secretpw']) + + self.cli_commit() + + config_file = f'/run/openvpn/{interface}.conf' + config = read_file(config_file) + + self.assertIn(f'dev vtun10', config) + self.assertIn(f'dev-type tun', config) + self.assertIn(f'persist-key', config) + self.assertIn(f'proto udp', config) + self.assertIn(f'rport {remote_port}', config) + self.assertIn(f'remote {remote_host}', config) + self.assertIn(f'persist-tun', config) + + # IPv4 only: client usees udp4 protocol + self.cli_set(path + ['ip-version', 'ipv4']) + self.cli_commit() + + config = read_file(config_file) + self.assertIn(f'proto udp4', config) + + # IPv6 only: client uses udp6 protocol + self.cli_set(path + ['ip-version', 'ipv6']) + self.cli_delete(path + ['remote-host', remote_host]) + self.cli_set(path + ['remote-host', remote_host_v6]) + self.cli_commit() + + config = read_file(config_file) + self.assertIn(f'proto udp6', config) + + # IPv6 dual-stack: not allowed in client mode + self.cli_set(path + ['ip-version', 'dual-stack']) + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_delete(base_path) + self.cli_commit() + def test_openvpn_server_verify(self): # Create one OpenVPN server interface and check required verify() stages interface = 'vtun5000' @@ -453,6 +514,74 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase): interface = f'vtun{ii}' self.assertNotIn(interface, interfaces()) + def test_openvpn_server_ip_version(self): + # Test the server mode behavior combined with each IP protocol version + + auth_hash = 'sha256' + port = '2000' + + interface = 'vtun20' + subnet = '192.0.20.0/24' + path = base_path + [interface] + + # Default behavior: client uses uspecified protocol version (udp) + self.cli_set(path + ['device-type', 'tun']) + self.cli_set(path + ['encryption', 'data-ciphers', 'aes192']) + self.cli_set(path + ['hash', auth_hash]) + self.cli_set(path + ['mode', 'server']) + self.cli_set(path + ['local-port', port]) + self.cli_set(path + ['server', 'subnet', subnet]) + self.cli_set(path + ['server', 'topology', 'subnet']) + + self.cli_set(path + ['replace-default-route']) + self.cli_set(path + ['tls', 'ca-certificate', 'ovpn_test']) + self.cli_set(path + ['tls', 'certificate', 'ovpn_test']) + self.cli_set(path + ['tls', 'dh-params', 'ovpn_test']) + + self.cli_commit() + + start_addr = inc_ip(subnet, '2') + stop_addr = last_host_address(subnet) + + config_file = f'/run/openvpn/{interface}.conf' + config = read_file(config_file) + + self.assertIn(f'dev {interface}', config) + self.assertIn(f'dev-type tun', config) + self.assertIn(f'persist-key', config) + self.assertIn(f'proto udp', config) # default protocol + self.assertIn(f'auth {auth_hash}', config) + self.assertIn(f'data-ciphers AES-192-CBC', config) + self.assertIn(f'topology subnet', config) + self.assertIn(f'lport {port}', config) + self.assertIn(f'push "redirect-gateway def1"', config) + + # IPv4 only: server usees udp4 protocol + self.cli_set(path + ['ip-version', 'ipv4']) + self.cli_commit() + + config = read_file(config_file) + self.assertIn(f'proto udp4', config) + + # IPv6 only: server uses udp6 protocol + bind ipv6only + self.cli_set(path + ['ip-version', 'ipv6']) + self.cli_commit() + + config = read_file(config_file) + self.assertIn(f'proto udp6', config) + self.assertIn(f'bind ipv6only', config) + + # IPv6 dual-stack: server uses udp6 protocol without bind ipv6only + self.cli_set(path + ['ip-version', 'dual-stack']) + self.cli_commit() + + config = read_file(config_file) + self.assertIn(f'proto udp6', config) + self.assertNotIn(f'bind ipv6only', config) + + self.cli_delete(base_path) + self.cli_commit() + def test_openvpn_site2site_verify(self): # Create one OpenVPN site2site interface and check required # verify() stages @@ -627,6 +756,63 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase): self.assertNotIn(interface, interfaces()) + def test_openvpn_site2site_ip_version(self): + # Test the site-to-site mode behavior combined with each IP protocol version + + encryption_cipher = 'aes256' + + interface = 'vtun30' + local_address = '192.0.30.1' + local_address_subnet = '255.255.255.252' + remote_address = '172.16.30.1' + path = base_path + [interface] + port = '3030' + + self.cli_set(path + ['local-address', local_address]) + self.cli_set(path + ['device-type', 'tun']) + self.cli_set(path + ['mode', 'site-to-site']) + self.cli_set(path + ['local-port', port]) + self.cli_set(path + ['remote-port', port]) + self.cli_set(path + ['shared-secret-key', 'ovpn_test']) + self.cli_set(path + ['remote-address', remote_address]) + self.cli_set(path + ['encryption', 'cipher', encryption_cipher]) + + self.cli_commit() + + config_file = f'/run/openvpn/{interface}.conf' + config = read_file(config_file) + + self.assertIn(f'dev-type tun', config) + self.assertIn(f'ifconfig {local_address} {remote_address}', config) + self.assertIn(f'proto udp', config) + self.assertIn(f'dev {interface}', config) + self.assertIn(f'secret /run/openvpn/{interface}_shared.key', config) + self.assertIn(f'lport {port}', config) + self.assertIn(f'rport {port}', config) + + # IPv4 only: server usees udp4 protocol + self.cli_set(path + ['ip-version', 'ipv4']) + self.cli_commit() + + config = read_file(config_file) + self.assertIn(f'proto udp4', config) + + # IPv6 only: server uses udp6 protocol + bind ipv6only + self.cli_set(path + ['ip-version', 'ipv6']) + self.cli_commit() + + config = read_file(config_file) + self.assertIn(f'proto udp6', config) + self.assertIn(f'bind ipv6only', config) + + # IPv6 dual-stack: not allowed in site-to-site mode + self.cli_set(path + ['ip-version', 'dual-stack']) + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_delete(base_path) + self.cli_commit() + def test_openvpn_server_server_bridge(self): # Create OpenVPN server interface using bridge. # Validate configuration afterwards. -- cgit v1.2.3