From 7ea3d8610d95986506d023f35fec270ca78c04cc Mon Sep 17 00:00:00 2001 From: Orion Poplawski Date: Fri, 5 Jan 2024 11:12:12 -0700 Subject: [PATCH] [pfsense_openvpn_client/override/server] Add better tunnel_network validation Fixes #77 --- plugins/module_utils/__impl/checks.py | 19 +++++++++++++++++++ plugins/module_utils/openvpn_client.py | 7 +++++++ plugins/module_utils/openvpn_override.py | 13 +++++++++---- plugins/module_utils/openvpn_server.py | 7 +++++++ plugins/module_utils/pfsense.py | 7 ++++++- .../modules/test_pfsense_openvpn_override.py | 2 +- 6 files changed, 49 insertions(+), 6 deletions(-) diff --git a/plugins/module_utils/__impl/checks.py b/plugins/module_utils/__impl/checks.py index b8525526..f6beebac 100644 --- a/plugins/module_utils/__impl/checks.py +++ b/plugins/module_utils/__impl/checks.py @@ -58,6 +58,25 @@ def check_ip_address(self, address, ipprotocol, objtype, allow_networks=False, f self.module.fail_json(msg='IPv4 and IPv6 addresses can not be used in objects that apply to both IPv4 and IPv6 (except within an alias).') +def validate_openvpn_tunnel_network(self, network, ipproto): + """ check openvpn tunnel network validity - based on pfSense's openvpn_validate_tunnel_network() """ + if network is not None and network != '': + alias_elt = self.find_alias(network, aliastype='network') + if alias_elt is not None: + networks = alias_elt.find('address').text.split() + if len(networks) > 1: + self.module.fail_json("The alias {0} contains more than one network".format(network)) + network = networks[0] + + if not self.is_ipv4_network(network, strict=False) and ipproto == 'ipv4': + self.module.fail_json("{0} is not a valid IPv4 network".format(network)) + if not self.is_ipv6_network(network, strict=False) and ipproto == 'ipv6': + self.module.fail_json("{0} is not a valid IPv6 network".format(network)) + return True + + return True + + def validate_string(self, name, objtype): """ check string validity - similar to pfSense's do_input_validate() """ diff --git a/plugins/module_utils/openvpn_client.py b/plugins/module_utils/openvpn_client.py index a774caeb..6bfba7d0 100644 --- a/plugins/module_utils/openvpn_client.py +++ b/plugins/module_utils/openvpn_client.py @@ -172,6 +172,13 @@ def _validate_params(self): # check name self.pfsense.validate_string(params['name'], 'openvpn') + if params['state'] == 'absent': + return True + + # check tunnel_networks - can be network alias or non-strict IP CIDR network + self.pfsense.validate_openvpn_tunnel_network(params.get('tunnel_network'), 'ipv4') + self.pfsense.validate_openvpn_tunnel_network(params.get('tunnel_network6'), 'ipv6') + # Check auth clients if len(params['authmode']) > 0: system = self.pfsense.get_element('system') diff --git a/plugins/module_utils/openvpn_override.py b/plugins/module_utils/openvpn_override.py index e4f0eaa0..2cd96bd8 100644 --- a/plugins/module_utils/openvpn_override.py +++ b/plugins/module_utils/openvpn_override.py @@ -54,6 +54,8 @@ class PFSenseOpenVPNOverrideModule(PFSenseModuleBase): """ module managing pfSense OpenVPN Client Specific Overrides """ + from ansible_collections.pfsensible.core.plugins.module_utils.__impl.checks import validate_openvpn_tunnel_network + @staticmethod def get_argument_spec(): """ return argument spec """ @@ -121,10 +123,13 @@ def _validate_params(self): # check name self.pfsense.validate_string(params['name'], 'openvpn_override') - if params.get('tunnel_network') and not self.pfsense.is_ipv4_network(params['tunnel_network']): - self.module.fail_json(msg='A valid IPv4 network must be specified for tunnel_network.') - if params.get('tunnel_network6') and not self.pfsense.is_ipv6_network(params['tunnel_networkv6']): - self.module.fail_json(msg='A valid IPv6 network must be specified for tunnel_network6.') + if params['state'] == 'absent': + return True + + # check tunnel_networks - can be network alias or non-strict IP CIDR network + self.pfsense.validate_openvpn_tunnel_network(params.get('tunnel_network'), 'ipv4') + self.pfsense.validate_openvpn_tunnel_network(params.get('tunnel_network6'), 'ipv6') + if params.get('local_network') and not self.pfsense.is_ipv4_network(params['local_network']): self.module.fail_json(msg='A valid IPv4 network must be specified for local_network.') if params.get('local_network6') and not self.pfsense.is_ipv6_network(params['local_networkv6']): diff --git a/plugins/module_utils/openvpn_server.py b/plugins/module_utils/openvpn_server.py index 445ab6ca..403369e2 100644 --- a/plugins/module_utils/openvpn_server.py +++ b/plugins/module_utils/openvpn_server.py @@ -202,6 +202,13 @@ def _validate_params(self): # check name self.pfsense.validate_string(params['name'], 'openvpn') + if params['state'] == 'absent': + return True + + # check tunnel_networks - can be network alias or non-strict IP CIDR network + self.pfsense.validate_openvpn_tunnel_network(params.get('tunnel_network'), 'ipv4') + self.pfsense.validate_openvpn_tunnel_network(params.get('tunnel_network6'), 'ipv6') + # Check auth servers if len(params['authmode']) > 0: system = self.pfsense.get_element('system') diff --git a/plugins/module_utils/pfsense.py b/plugins/module_utils/pfsense.py index 7a478ab5..77bf09c8 100644 --- a/plugins/module_utils/pfsense.py +++ b/plugins/module_utils/pfsense.py @@ -56,7 +56,12 @@ class PFSenseModule(object): parse_ip_network, parse_port, ) - from ansible_collections.pfsensible.core.plugins.module_utils.__impl.checks import check_name, check_ip_address, validate_string + from ansible_collections.pfsensible.core.plugins.module_utils.__impl.checks import ( + check_name, + check_ip_address, + validate_string, + validate_openvpn_tunnel_network, + ) def __init__(self, module, config='/cf/conf/config.xml'): self.module = module diff --git a/tests/unit/plugins/modules/test_pfsense_openvpn_override.py b/tests/unit/plugins/modules/test_pfsense_openvpn_override.py index 530d1f2f..09665992 100644 --- a/tests/unit/plugins/modules/test_pfsense_openvpn_override.py +++ b/tests/unit/plugins/modules/test_pfsense_openvpn_override.py @@ -74,7 +74,7 @@ def test_openvpn_override_update_noop(self): def test_openvpn_override_update_network(self): """ test updating network of a OpenVPN override """ - obj = dict(name='delvpnuser', gwredir=True, server_list=1, custom_options='ifconfig-push 10.8.0.1 255.255.255.0', tunnel_network='10.10.10.0/24') + obj = dict(name='delvpnuser', gwredir=True, server_list=1, custom_options='ifconfig-push 10.8.0.1 255.255.255.0', tunnel_network='10.10.10.10/24') self.do_module_test(obj, command="update openvpn_override 'delvpnuser' set ") ##############