From ceb1a8d6b6144d7c44a2e1f0b16b5afecc43f904 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 1 Nov 2022 22:35:48 +0100 Subject: openvpn: T3214: allow configuring server with v6 only Starting with v2.5.0 OpenVPN allows configuring a server with an IPv6 only tunnel. For this reason there is no need to depend on the existence of an IPv4 subnet anymore. Signed-off-by: Antonio Quartulli (cherry picked from commit 3072e507eb1cdc18cfe5429fd0c03d223d2576fe) --- src/conf_mode/interfaces_openvpn.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/conf_mode/interfaces_openvpn.py b/src/conf_mode/interfaces_openvpn.py index 5795ce0bc..28f323691 100755 --- a/src/conf_mode/interfaces_openvpn.py +++ b/src/conf_mode/interfaces_openvpn.py @@ -347,9 +347,6 @@ def verify(openvpn): if v6_subnets > 1: raise ConfigError('Cannot specify more than 1 IPv6 server subnet') - if v6_subnets > 0 and v4_subnets == 0: - raise ConfigError('IPv6 server requires an IPv4 server subnet') - for subnet in tmp: if is_ipv4(subnet): subnet = IPv4Network(subnet) -- cgit v1.2.3 From 72fefd8269a55e1626fd00bad8cda908604f9325 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 1 Nov 2022 22:43:46 +0100 Subject: openvpn: T3214: warn when setting nopool and server-ipv6 is being used Currently OpenVPN does not allow having an IPv6 subnet if 'nopool' was specified on the --server directive. For this eason warn if this specific configuration is being hit. This is probably something that should be fixed upstream, but for now we can't allow this combination of parameters. Signed-off-by: Antonio Quartulli (cherry picked from commit 7a0e40ce8df386c0ea2de84bce8fb6c81a0353ce) --- src/conf_mode/interfaces_openvpn.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/conf_mode/interfaces_openvpn.py b/src/conf_mode/interfaces_openvpn.py index 28f323691..45569dd21 100755 --- a/src/conf_mode/interfaces_openvpn.py +++ b/src/conf_mode/interfaces_openvpn.py @@ -388,6 +388,10 @@ def verify(openvpn): for v4PoolNet in v4PoolNets: if IPv4Address(client['ip'][0]) in v4PoolNet: print(f'Warning: Client "{client["name"]}" IP {client["ip"][0]} is in server IP pool, it is not reserved for this client.') + # configuring a client_ip_pool will set 'server ... nopool' which is currently incompatible with 'server-ipv6' (probably to be fixed upstream) + for subnet in (dict_search('server.subnet', openvpn) or []): + if is_ipv6(subnet): + raise ConfigError(f'Setting client-ip-pool is incompatible having an IPv6 server subnet.') for subnet in (dict_search('server.subnet', openvpn) or []): if is_ipv6(subnet): -- cgit v1.2.3 From 49efd22c36ab1a14d87d8d91ef50edf23c2c7b4a Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 1 Nov 2022 22:52:49 +0100 Subject: openvpn: T3214: specify nopool on --server line only if needed The --server directive will already create a pool automatically. For this reason noppol should be used only when an explicit client-ip-pool was configured by the user. If that's not the case, then the nopool flag should not be specified and no manual pool should be configured. Signed-off-by: Antonio Quartulli (cherry picked from commit 0ccbbca01b22232b5cba63d64ab00eb54af7b068) --- data/templates/openvpn/server.conf.j2 | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/data/templates/openvpn/server.conf.j2 b/data/templates/openvpn/server.conf.j2 index b9dfe23ad..64c8e8086 100644 --- a/data/templates/openvpn/server.conf.j2 +++ b/data/templates/openvpn/server.conf.j2 @@ -74,7 +74,7 @@ topology {{ server.topology }} {% endif %} {% for subnet in server.subnet %} {% if subnet | is_ipv4 %} -server {{ subnet | address_from_cidr }} {{ subnet | netmask_from_cidr }} nopool +server {{ subnet | address_from_cidr }} {{ subnet | netmask_from_cidr }} {{ 'nopool' if server.client_ip_pool is vyos_defined and server.client_ip_pool.disable is not vyos_defined else '' }} {# First ip address is used as gateway. It's allows to use metrics #} {% if server.push_route is vyos_defined %} {% for route, route_config in server.push_route.items() %} @@ -85,15 +85,6 @@ push "route-ipv6 {{ route }}" {% endif %} {% endfor %} {% endif %} -{# OpenVPN assigns the first IP address to its local interface so the pool used #} -{# in net30 topology - where each client receives a /30 must start from the second subnet #} -{% if server.topology is vyos_defined('net30') %} -ifconfig-pool {{ subnet | inc_ip('4') }} {{ subnet | last_host_address | dec_ip('1') }} {{ subnet | netmask_from_cidr if device_type == 'tap' else '' }} -{% else %} -{# OpenVPN assigns the first IP address to its local interface so the pool must #} -{# start from the second address and end on the last address #} -ifconfig-pool {{ subnet | first_host_address | inc_ip('1') }} {{ subnet | last_host_address | dec_ip('1') }} {{ subnet | netmask_from_cidr if device_type == 'tun' else '' }} -{% endif %} {% elif subnet | is_ipv6 %} server-ipv6 {{ subnet }} {% endif %} -- cgit v1.2.3 From 7e4d6896b2e1b84837ac07488f518627405270eb Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Fri, 15 Sep 2023 07:02:14 +0200 Subject: smoketests: drop nopool/net30 from testcases After commit 0ccbbca01b ("openvpn: T3214: specify nopool on --server line only if needed") that removed the net30 option and nopool smoketests needed a fix. (cherry picked from commit 455943cd7f759a5a3fc53d421b479044730d1f08) --- smoketest/scripts/cli/test_interfaces_openvpn.py | 76 +----------------------- 1 file changed, 1 insertion(+), 75 deletions(-) diff --git a/smoketest/scripts/cli/test_interfaces_openvpn.py b/smoketest/scripts/cli/test_interfaces_openvpn.py index d1ece84d6..4a7e2418c 100755 --- a/smoketest/scripts/cli/test_interfaces_openvpn.py +++ b/smoketest/scripts/cli/test_interfaces_openvpn.py @@ -421,7 +421,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase): # IP pool configuration netmask = IPv4Network(subnet).netmask network = IPv4Network(subnet).network_address - self.assertIn(f'server {network} {netmask} nopool', config) + self.assertIn(f'server {network} {netmask}', config) # Verify client client_config = read_file(client_config_file) @@ -442,80 +442,6 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase): interface = f'vtun{ii}' self.assertNotIn(interface, interfaces()) - def test_openvpn_server_net30_topology(self): - # Create OpenVPN server interfaces (net30) using different client - # subnets. Validate configuration afterwards. - auth_hash = 'sha256' - num_range = range(20, 25) - port = '' - for ii in num_range: - interface = f'vtun{ii}' - subnet = f'192.0.{ii}.0/24' - path = base_path + [interface] - port = str(2000 + ii) - - self.cli_set(path + ['device-type', 'tun']) - self.cli_set(path + ['encryption', 'cipher', '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', 'net30']) - self.cli_set(path + ['replace-default-route']) - self.cli_set(path + ['keep-alive', 'failure-count', '10']) - self.cli_set(path + ['keep-alive', 'interval', '5']) - 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_set(path + ['vrf', vrf_name]) - - self.cli_commit() - - for ii in num_range: - interface = f'vtun{ii}' - subnet = f'192.0.{ii}.0/24' - start_addr = inc_ip(subnet, '4') - stop_addr = dec_ip(last_host_address(subnet), '1') - port = str(2000 + ii) - - 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'cipher AES-192-CBC', config) - self.assertIn(f'topology net30', config) - self.assertIn(f'lport {port}', config) - self.assertIn(f'push "redirect-gateway def1"', config) - self.assertIn(f'keepalive 5 50', config) - - # TLS options - self.assertIn(f'ca /run/openvpn/{interface}_ca.pem', config) - self.assertIn(f'cert /run/openvpn/{interface}_cert.pem', config) - self.assertIn(f'key /run/openvpn/{interface}_cert.key', config) - self.assertIn(f'dh /run/openvpn/{interface}_dh.pem', config) - - # IP pool configuration - netmask = IPv4Network(subnet).netmask - network = IPv4Network(subnet).network_address - self.assertIn(f'server {network} {netmask} nopool', config) - self.assertIn(f'ifconfig-pool {start_addr} {stop_addr}', config) - - self.assertTrue(process_named_running(PROCESS_NAME)) - self.assertEqual(get_vrf(interface), vrf_name) - self.assertIn(interface, interfaces()) - - # check that no interface remained after deleting them - self.cli_delete(base_path) - self.cli_commit() - - for ii in num_range: - interface = f'vtun{ii}' - self.assertNotIn(interface, interfaces()) - def test_openvpn_site2site_verify(self): # Create one OpenVPN site2site interface and check required # verify() stages -- cgit v1.2.3