Skip to content

Commit

Permalink
Merge pull request #297 from abates:issue-295
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 629448976
  • Loading branch information
Capirca Team committed Apr 30, 2024
2 parents aa8d408 + d84253b commit fe2f526
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 18 deletions.
20 changes: 12 additions & 8 deletions capirca/lib/cisco.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,8 +807,8 @@ class ObjectGroupTerm(Term):
# Protocols should be emitted as integers rather than strings.
_PROTO_INT = True

def __init__(self, term, filter_name, platform='cisco', verbose=True):
super().__init__(term)
def __init__(self, term, filter_name, af=4, platform='cisco', verbose=True):
super().__init__(term, af=af)
self.term = term
self.filter_name = filter_name
self.platform = platform
Expand Down Expand Up @@ -947,8 +947,8 @@ def _TranslatePolicy(self, pol, exp_info):
exp_info_date = current_date + datetime.timedelta(weeks=exp_info)

# a mixed filter outputs both ipv4 and ipv6 acls in the same output file
good_filters = ['extended', 'standard', 'object-group', 'inet6',
'mixed', 'enable_dsmo']
good_filters = ['extended', 'standard', 'object-group',
'object-group-inet6', 'inet6', 'mixed', 'enable_dsmo']

for header, terms in pol.filters:
if self._PLATFORM not in header.platforms:
Expand Down Expand Up @@ -1065,6 +1065,10 @@ def _TranslatePolicy(self, pol, exp_info):
term, filter_name, verbose=self.verbose
)
)
elif next_filter == 'object-group-inet6':
obj_target.AddTerm(term)
new_terms.append(self._GetObjectGroupTerm(term, filter_name, af=6,
verbose=self.verbose))
elif next_filter == 'inet6':
new_terms.append(
Term(
Expand All @@ -1083,9 +1087,9 @@ def _TranslatePolicy(self, pol, exp_info):
(header, filter_name, [next_filter], new_terms, obj_target)
)

def _GetObjectGroupTerm(self, term, filter_name, verbose=True):
def _GetObjectGroupTerm(self, term, filter_name, af=4, verbose=True):
"""Returns an ObjectGroupTerm object."""
return ObjectGroupTerm(term, filter_name, verbose=verbose)
return ObjectGroupTerm(term, filter_name, af=af, verbose=verbose)

def _remove_duplicate_objects(self, target):
"""Remove all duplicate object-groups and rename to the first group found.
Expand Down Expand Up @@ -1281,7 +1285,7 @@ def _AppendTargetByFilterType(self, filter_name, filter_type):
elif filter_type == 'object-group':
target.append('no ip access-list extended %s' % filter_name)
target.append('ip access-list extended %s' % filter_name)
elif filter_type == 'inet6':
elif filter_type == 'inet6' or filter_type == 'object-group-inet6':
target.append('no ipv6 access-list %s' % filter_name)
target.append('ipv6 access-list %s' % filter_name)
else:
Expand Down Expand Up @@ -1311,7 +1315,7 @@ def __str__(self):
) in self.cisco_policies:
for filter_type in filter_list:
target.extend(self._AppendTargetByFilterType(filter_name, filter_type))
if filter_type == 'object-group':
if filter_type == 'object-group' or filter_type == 'object-group-inet6':
obj_target.AddName(filter_name)

# Add the Perforce Id/Date tags, these must come after
Expand Down
2 changes: 1 addition & 1 deletion capirca/lib/cisconx.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def _AppendTargetByFilterType(self, filter_name, filter_type):
elif filter_type == 'object-group':
target.append('no ip access-list %s' % filter_name)
target.append('ip access-list %s' % filter_name)
elif filter_type == 'inet6':
elif filter_type == 'inet6' or filter_type == 'object-group-inet6':
target.append('no ipv6 access-list %s' % filter_name)
target.append('ipv6 access-list %s' % filter_name)
else:
Expand Down
6 changes: 3 additions & 3 deletions capirca/lib/ciscoxr.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def _AppendTargetByFilterType(self, filter_name, filter_type):
list of strings
"""
target = []
if filter_type == 'inet6':
if filter_type == 'inet6' or filter_type == 'object-group-inet6':
target.append('no ipv6 access-list %s' % filter_name)
target.append('ipv6 access-list %s' % filter_name)
else:
Expand All @@ -57,9 +57,9 @@ def _BuildTokens(self):

return supported_tokens, supported_sub_tokens

def _GetObjectGroupTerm(self, term, filter_name, verbose=True):
def _GetObjectGroupTerm(self, term, filter_name, af=4, verbose=True):
"""Returns an ObjectGroupTerm object."""
return CiscoXRObjectGroupTerm(term, filter_name,
return CiscoXRObjectGroupTerm(term, filter_name, af=af,
platform=self._PLATFORM, verbose=verbose)


Expand Down
3 changes: 2 additions & 1 deletion doc/generators/cisco.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

The cisco header designation has the following format:
```
target:: cisco [filter name] {extended|standard|object-group|inet6|mixed} {dsmo}
target:: cisco [filter name] {extended|standard|object-group|object-group-inet6|inet6|mixed} {dsmo}
```
* _filter name_: defines the name or number of the cisco filter.
* _extended_: specifies that the output should be an extended access list, and the filter name should be non-numeric. This is the default option.
* _standard_: specifies that the output should be a standard access list, and the filter name should be numeric and in the range of 1-99.
* _object-group_: specifies this is a cisco extended access list, and that object-groups should be used for ports and addresses.
* _object-group-inet6_: specifies this is a cisco extended ipv6 access list, and that object-groups should be used for ports and addresses.
* _inet6_: specifies the output be for IPv6 only filters.
* _mixed_: specifies output will include both IPv6 and IPv4 filters.
* _dsmo_: Enable discontinuous subnet mask summarization.
Expand Down
64 changes: 61 additions & 3 deletions tests/lib/cisco_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
target:: cisco 50 standard
}
"""
GOOD_OBJGRP_HEADER = """
GOOD_OBJGRP_HEADER_1 = """
header {
comment:: "obj group header test"
target:: cisco objgroupheader object-group
Expand All @@ -62,6 +62,12 @@
target:: cisco objgroupheader object-group remove_duplicate_network_objectgroups
}
"""
GOOD_OBJGRP_HEADER_2 = """
header {
comment:: "obj group header test"
target:: cisco objgroupheader object-group-inet6
}
"""
GOOD_INET6_HEADER = """
header {
comment:: "inet6 header test"
Expand Down Expand Up @@ -653,9 +659,8 @@ def testObjectGroup(self):
self.naming.GetServiceByProto.return_value = ['80']

pol = policy.ParsePolicy(
GOOD_OBJGRP_HEADER + GOOD_TERM_2 + GOOD_TERM_18, self.naming)
GOOD_OBJGRP_HEADER_1 + GOOD_TERM_2 + GOOD_TERM_18, self.naming)
acl = cisco.Cisco(pol, EXP_INFO)

self.assertIn('\n'.join(ip_grp), str(acl), '%s %s' % (
'\n'.join(ip_grp), str(acl)))
self.assertIn('\n'.join(port_grp1), str(acl), '%s %s' % (
Expand Down Expand Up @@ -748,6 +753,59 @@ def testObjectGroupNoDuplicates(self):
)
self.naming.GetServiceByProto.assert_called_with('HTTP', 'tcp')

def testObjectGroupInet6(self):
ip_grp = ['object-group network ipv6 SOME_HOST']
ip_grp.append(' 2001::3/128')
ip_grp.append('exit')
port_grp1 = ['object-group port 80-80']
port_grp1.append(' eq 80')
port_grp1.append('exit')
port_grp2 = ['object-group port 1024-65535']
port_grp2.append(' range 1024 65535')
port_grp2.append('exit')

self.naming.GetNetAddr.return_value = [
nacaddr.IP('2001::3/128', token='SOME_HOST')]
self.naming.GetServiceByProto.return_value = ['80']

pol = policy.ParsePolicy(
GOOD_OBJGRP_HEADER_2 + GOOD_TERM_2 + GOOD_TERM_18, self.naming)
acl = cisco.Cisco(pol, EXP_INFO)
self.assertIn('\n'.join(ip_grp), str(acl), '%s %s' % (
'\n'.join(ip_grp), str(acl)))
self.assertIn('\n'.join(port_grp1), str(acl), '%s %s' % (
'\n'.join(port_grp1), str(acl)))
self.assertIn('\n'.join(port_grp2), str(acl), '%s %s' % (
'\n'.join(port_grp2), str(acl)))

# Object-group terms should use the object groups created.
self.assertIn(
' permit tcp any port-group 80-80 net-group SOME_HOST port-group'
' 1024-65535', str(acl), str(acl))
self.assertIn(
' permit ipv6 net-group SOME_HOST net-group SOME_HOST', str(acl),
str(acl))

# There should be no addrgroups that look like IP addresses.
for addrgroup in re.findall(r'net-group ([a-f0-9.:/]+)', str(acl)):
self.assertRaises(ValueError, nacaddr.IP(addrgroup))

self.naming.GetNetAddr.assert_has_calls([mock.call('SOME_HOST'),
mock.call('SOME_HOST')])
self.naming.GetServiceByProto.assert_called_once_with('HTTP', 'tcp')

# There should be no ipv4 addresses
self.naming.GetNetAddr.reset_mock()
self.naming.GetNetAddr.return_value = [
nacaddr.IP('192.168.0.1/32', token='SOME_HOST'),
]
pol = policy.ParsePolicy(
GOOD_OBJGRP_HEADER_2 + GOOD_TERM_2 + GOOD_TERM_18, self.naming)
acl = cisco.Cisco(pol, EXP_INFO)
self.assertNotIn(' permit ip net-group SOME_HOST net-group SOME_HOST', str(acl))
self.naming.GetNetAddr.assert_has_calls([mock.call('SOME_HOST'),
mock.call('SOME_HOST')])

def testInet6(self):
self.naming.GetNetAddr.return_value = [nacaddr.IP('10.0.0.0/8'),
nacaddr.IP('2001:4860:8000::/33')]
Expand Down
24 changes: 22 additions & 2 deletions tests/lib/ciscoxr_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
from capirca.lib import naming
from capirca.lib import policy

OBJECT_GROUP_HEADER = """
header {
target:: ciscoxr foo object-group
}
"""

GOOD_HEADER_1 = """
header {
Expand All @@ -36,11 +41,18 @@
}
"""

OBJECT_GROUP_HEADER = """
OBJECT_GROUP_HEADER_1 = """
header {
target:: ciscoxr foo object-group
}
"""

OBJECT_GROUP_HEADER_2 = """
header {
target:: ciscoxr foo object-group-inet6
}
"""

GOOD_TERM_1 = """
term good-term-1 {
source-address:: SOME_HOST
Expand Down Expand Up @@ -324,7 +336,7 @@ def testBuildWarningTokens(self):

def testVerbatimObjectGroup(self):
self.naming.GetNetAddr.return_value = [nacaddr.IP('10.1.1.1/32')]
pol = policy.ParsePolicy(OBJECT_GROUP_HEADER + VERBATIM_TERM, self.naming)
pol = policy.ParsePolicy(OBJECT_GROUP_HEADER_1 + VERBATIM_TERM, self.naming)
acl = ciscoxr.CiscoXR(pol, EXP_INFO)
self.assertIn('permit tcp any', str(acl))

Expand All @@ -335,5 +347,13 @@ def testObjectGroup(self):
self.assertIn('permit ipv4 any', str(acl))


def testVerbatimObjectGroupIPv6(self):
self.naming.GetNetAddr.return_value = [nacaddr.IP('2001::3/128')]
pol = policy.ParsePolicy(OBJECT_GROUP_HEADER_2 + VERBATIM_TERM, self.naming)
acl = ciscoxr.CiscoXR(pol, EXP_INFO)
self.assertIn('permit tcp any', str(acl))
self.assertIn('ipv6 access-list foo', str(acl))


if __name__ == '__main__':
absltest.main()

0 comments on commit fe2f526

Please sign in to comment.