From 37a5d78274a024e3fa91e6b193e8e5f3ecc8d4cc Mon Sep 17 00:00:00 2001 From: Valentin Doreau Date: Sun, 30 Nov 2025 13:19:21 +0100 Subject: [PATCH] [pfsense_rule] Allow IPv6 addresses in source/destination Do not split on : if parsing ipv6. This also assumes you're not going to use ipv6:port syntax which is deprecated Adds tests Fixes #219 --- changelogs/fragemnts/219_parse_address_ipv6.yml | 2 ++ plugins/module_utils/__impl/addresses.py | 9 ++++++--- tests/unit/plugins/modules/test_pfsense_rule.py | 6 +++++- .../unit/plugins/modules/test_pfsense_rule_create.py | 12 ++++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 changelogs/fragemnts/219_parse_address_ipv6.yml diff --git a/changelogs/fragemnts/219_parse_address_ipv6.yml b/changelogs/fragemnts/219_parse_address_ipv6.yml new file mode 100644 index 00000000..76649e64 --- /dev/null +++ b/changelogs/fragemnts/219_parse_address_ipv6.yml @@ -0,0 +1,2 @@ +bugfixes: + - pfsense_rule - Allow IPv6 addresses in source and destination (https://github.com/pfsensible/core/issues/219). diff --git a/plugins/module_utils/__impl/addresses.py b/plugins/module_utils/__impl/addresses.py index f53e96a0..121357bf 100644 --- a/plugins/module_utils/__impl/addresses.py +++ b/plugins/module_utils/__impl/addresses.py @@ -103,9 +103,12 @@ def parse_ip_network(address, strict=True, returns_ip=True): def parse_address(self, param, allow_self=True): """ validate param address field and returns it as a dict """ - addr = param.split(':') - if len(addr) > 3: - self.module.fail_json(msg='Cannot parse address %s' % (param)) + if self.is_ipv6_address(param) or self.is_ipv6_network(param): + addr = [param] + else: + addr = param.split(':', maxsplit=3) + if len(addr) > 3: + self.module.fail_json(msg='Cannot parse address %s' % (param)) address = addr[0] diff --git a/tests/unit/plugins/modules/test_pfsense_rule.py b/tests/unit/plugins/modules/test_pfsense_rule.py index 90bfbbe8..f6dbc2ce 100644 --- a/tests/unit/plugins/modules/test_pfsense_rule.py +++ b/tests/unit/plugins/modules/test_pfsense_rule.py @@ -12,6 +12,7 @@ from ansible_collections.pfsensible.core.plugins.modules import pfsense_rule from ansible_collections.pfsensible.core.plugins.module_utils.rule import PFSenseRuleModule +from ansible_collections.pfsensible.core.plugins.module_utils.__impl.addresses import is_ipv6_address, is_ipv6_network from .pfsense_module import TestPFSenseModule @@ -31,7 +32,10 @@ def runTest(): def parse_address(self, addr): """ return address parsed in dict """ - parts = addr.split(':') + if is_ipv6_address(addr) or is_ipv6_network(addr): + parts = [addr] + else: + parts = addr.split(':') res = {} if parts[0][0] == '!': res['not'] = None diff --git a/tests/unit/plugins/modules/test_pfsense_rule_create.py b/tests/unit/plugins/modules/test_pfsense_rule_create.py index fd2fa61d..f300e07f 100644 --- a/tests/unit/plugins/modules/test_pfsense_rule_create.py +++ b/tests/unit/plugins/modules/test_pfsense_rule_create.py @@ -329,12 +329,24 @@ def test_rule_create_ip_to_ip(self): command = "create rule 'one_rule' on 'lan', source='10.10.1.1', destination='10.10.10.1'" self.do_module_test(obj, command=command) + def test_rule_create_ip6_to_ip6(self): + """ test creation of a new rule with valid ips """ + obj = dict(name='one_rule', source='2001:db8:1::1', destination='2001:db8:2::2', ipprotocol='inet6', interface='lan') + command = "create rule 'one_rule' on 'lan', source='2001:db8:1::1', destination='2001:db8:2::2', ipprotocol='inet6'" + self.do_module_test(obj, command=command) + def test_rule_create_net_to_net(self): """ test creation of a new rule valid networks """ obj = dict(name='one_rule', source='10.10.1.0/24', destination='10.10.10.0/24', interface='lan') command = "create rule 'one_rule' on 'lan', source='10.10.1.0/24', destination='10.10.10.0/24'" self.do_module_test(obj, command=command) + def test_rule_create_net6_to_net6(self): + """ test creation of a new rule valid networks """ + obj = dict(name='one_rule', source='2001:db8:1::/64', destination='2001:db8:2::/64', ipprotocol='inet6', interface='lan') + command = "create rule 'one_rule' on 'lan', source='2001:db8:1::/64', destination='2001:db8:2::/64', ipprotocol='inet6'" + self.do_module_test(obj, command=command) + def test_rule_create_net_interface(self): """ test creation of a new rule with valid interface """ obj = dict(name='one_rule', source='NET:lan', destination='any', interface='lan')