diff --git a/ciscoconfparse/ccp_util.py b/ciscoconfparse/ccp_util.py index 5d5f06c..24d61aa 100644 --- a/ciscoconfparse/ccp_util.py +++ b/ciscoconfparse/ccp_util.py @@ -91,19 +91,20 @@ _RGX_CISCO_RANGE = re.compile(_CISCO_RANGE_STR) ####################### Begin IPv6 ############################# -_IPV6_REGEX_STR = r"""(?!:::\S+?$) # Negative Lookahead for 3 colons - (?P # Begin a group named 'addr' - (?P{0}(?::{0}){{7}}) # no double colons, option 1 -|(?P(?:{0}:){{1}}(?::{0}){{1,6}}) # match fe80::1 -|(?P(?:{0}:){{2}}(?::{0}){{1,5}}) # match fe80:a::1 -|(?P(?:{0}:){{3}}(?::{0}){{1,4}}) # match fe80:a:b::1 -|(?P(?:{0}:){{4}}(?::{0}){{1,3}}) # match fe80:a:b:c::1 -|(?P(?:{0}:){{5}}(?::{0}){{1,2}}) # match fe80:a:b:c:d::1 -|(?P(?:{0}:){{6}}(?::{0}){{1,1}}) # match fe80:a:b:c:d:e::1 -|(?P:(?::{0}){{1,7}}) # ipv6 with leading double colons -|(?P(?:{0}:){{1,7}}:) # ipv6 with trailing double colons -|(?P(?:::)) # ipv6 bare double colons (default route) -)([/\s](?P\d+))* # match 'masklen' and end 'addr' group +_IPV6_REGEX_STR = r"""(?!:::\S+?$) # Negative Lookahead for 3 colons + (?P # Begin a group named 'addr' + (?P{0}(?::{0}){{7}}) # no double colons, option 1 +|(?P[0-9a-fA-F\:]+?\d+\.\d+\.\d+\.\d+) # ipv4 embedded in an ipv6 address +|(?P(?:{0}:){{1}}(?::{0}){{1,6}}) # match fe80::1 +|(?P(?:{0}:){{2}}(?::{0}){{1,5}}) # match fe80:a::1 +|(?P(?:{0}:){{3}}(?::{0}){{1,4}}) # match fe80:a:b::1 +|(?P(?:{0}:){{4}}(?::{0}){{1,3}}) # match fe80:a:b:c::1 +|(?P(?:{0}:){{5}}(?::{0}){{1,2}}) # match fe80:a:b:c:d::1 +|(?P(?:{0}:){{6}}(?::{0}){{1,1}}) # match fe80:a:b:c:d:e::1 +|(?P:(?::{0}){{1,7}}) # ipv6 with leading double colons +|(?P(?:{0}:){{1,7}}:) # ipv6 with trailing double colons +|(?P(?:::)) # ipv6 bare double colons (default route) +)([/\s](?P\d+))* # match 'masklen' and end 'addr' group """.format(_IPV6_RGX_CLS) _IPV6_REGEX_STR_COMPRESSED1 = r"""(?!:::\S+?$)(?P(?P{0}(?::{0}){{7}})|(?P(?:{0}:){{1}}(?::{0}){{1,6}})|(?P(?:{0}:){{2}}(?::{0}){{1,5}})|(?P(?:{0}:){{3}}(?::{0}){{1,4}})|(?P(?:{0}:){{4}}(?::{0}){{1,3}})|(?P(?:{0}:){{5}}(?::{0}){{1,2}})|(?P(?:{0}:){{6}}(?::{0}){{1,1}})|(?P:(?::{0}){{1,7}})|(?P(?:{0}:){{1,7}}:)|(?P(?:::)))""".format(_IPV6_RGX_CLS) @@ -1879,7 +1880,7 @@ def __init__(self, v6addr_prefixlen=None, strict=False, debug=0): # Example 'v6_groupdict' # v6_groupdict = {'addr': '2b00:cd80:14:10::1', 'opt1': None, 'opt2': None, 'opt3': None, 'opt4': None, 'opt5': '2b00:cd80:14:10::1', 'opt6': None, 'opt7': None, 'opt8': None, 'opt9': None, 'opt10': None, 'masklen': '64'} v6_groupdict = v6_str_rgx.groupdict() - for key in ["addr", "opt1", "opt2", "opt3", "opt4", "opt5", "opt6", "opt7", "opt8", "opt9", "opt10",]: + for key in ["addr", "opt1", "opt2", "opt3", "opt4", "opt5", "opt6", "opt7", "opt8", "opt9", "opt10", "opt11"]: _ipv6 = v6_groupdict[key] if _ipv6 is not None: break diff --git a/ciscoconfparse/models_cisco.py b/ciscoconfparse/models_cisco.py index 9dbe4aa..d929bad 100644 --- a/ciscoconfparse/models_cisco.py +++ b/ciscoconfparse/models_cisco.py @@ -2283,10 +2283,9 @@ def trunk_vlans_allowed(self): elif vdict["allowed"] != "_nomatch_": retval = CiscoRange(vdict["allowed"], result_type=int) - print("----") + # Inspect vdict keys in a specific order to ensure best results... for key in ["allowed", "add", "except", "remove"]: _value = vdict[key] - print(f"KEY: {key}, VALUE: {_value}") if isinstance(_value, str): _value = _value.strip() diff --git a/tests/test_Ccp_Util.py b/tests/test_Ccp_Util.py index fc9099f..5294052 100755 --- a/tests/test_Ccp_Util.py +++ b/tests/test_Ccp_Util.py @@ -597,12 +597,25 @@ def testIPv6Obj_lt_01(): """Simple less_than test""" assert IPv6Obj("::1") < IPv6Obj("::2") +def testIPv6Obj_IPv4_embedded_in_IPv6_01(): + """Test IPv6Obj with an IPv4 address (192.168.1.254) embedded in an IPv6 address""" + assert IPv6Obj("::192.168.1.254") == IPv6Obj("::c0a8:1fe") -def test_collapse_addresses_01(): +def testIPv6Obj_IPv4_embedded_in_IPv6_02(): + """Test IPv6Obj with an IPv4 address (192.0.2.33) embedded in an IPv6 address""" + assert IPv6Obj("2001:db8:122:344::192.0.2.33") == IPv6Obj("2001:db8:122:344::c000:221") - net_collapsed = ipaddress.collapse_addresses([IPv4Network('192.0.0.0/22'), IPv4Network('192.0.2.128/25')]) +def testIPv6Obj_IPv4_embedded_in_IPv6_03(): + """Test IPv6Obj with an RFC 6052 NAT64 prefix (64:ff9b::) using IPv4 address (10.20.0.1) embedded in an IPv6 address""" + assert IPv6Obj("64:ff9b::192.0.2.33") == IPv6Obj("64:ff9b::c000:221") +def testIPv6Obj_IPv4_embedded_in_IPv6_04(): + """Test IPv6Obj with an IPv4 address (192.0.2.4) embedded in an IPv6 address""" + assert IPv6Obj("::ffff:192.0.2.4") == IPv6Obj("::ffff:c000:204") +def test_collapse_addresses_01(): + + net_collapsed = ipaddress.collapse_addresses([IPv4Network('192.0.0.0/22'), IPv4Network('192.0.2.128/25')]) for idx, entry in enumerate(net_collapsed): if idx==0: assert entry == IPv4Network("192.0.0.0/22")