Skip to content

Commit 0f3400f

Browse files
author
Capirca Team
committedAug 16, 2022
Add support for zone filtering for global srx policies
PiperOrigin-RevId: 467965304
1 parent 5635489 commit 0f3400f

File tree

6 files changed

+122
-2
lines changed

6 files changed

+122
-2
lines changed
 

‎capirca/lib/junipersrx.py

+26
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,22 @@ def __str__(self):
169169
ret_str.IndentAppend(5, JunipersrxList('dscp-except',
170170
self.term.dscp_except))
171171

172+
# SOURCE-ZONE
173+
if self.term.source_zone:
174+
szone_check = set()
175+
for szone in self.term.source_zone:
176+
szone_check.add(szone)
177+
szone_check = sorted(szone_check)
178+
ret_str.IndentAppend(5, JunipersrxList('from-zone', szone_check))
179+
180+
# DESTINATION-ZONE
181+
if self.term.destination_zone:
182+
dzone_check = set()
183+
for dzone in self.term.destination_zone:
184+
dzone_check.add(dzone)
185+
dzone_check = sorted(dzone_check)
186+
ret_str.IndentAppend(5, JunipersrxList('to-zone', dzone_check))
187+
172188
ret_str.IndentAppend(4, '}')
173189

174190
# ACTIONS
@@ -307,9 +323,11 @@ def _BuildTokens(self):
307323
supported_tokens |= {'dscp_except',
308324
'dscp_match',
309325
'dscp_set',
326+
'destination_zone',
310327
'logging',
311328
'option',
312329
'owner',
330+
'source_zone',
313331
'timeout',
314332
'verbatim',
315333
'vpn'}
@@ -375,6 +393,14 @@ def _TranslatePolicy(self, pol, exp_info):
375393
else:
376394
self.to_zone = filter_options[3]
377395

396+
# check if source-zone & destination-zone are only used with global policy
397+
if filter_options[1] != 'all' or filter_options[3] != 'all':
398+
for term in terms:
399+
if term.source_zone or term.destination_zone:
400+
raise UnsupportedFilterError('Term %s has either source-zone or '
401+
'destination-zone which can only be '
402+
'used with global policy' % term.name)
403+
378404
# variables used to collect target-options and set defaults
379405
filter_type = ''
380406

‎capirca/lib/policy.py

+44
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,8 @@ class Term:
333333
pan-application: VarType.PAN_APPLICATION
334334
policer: VarType.POLICER
335335
priority: VarType.PRIORITY
336+
destination-zone: VarType.DZONE
337+
source-zone: VarType.SZONE
336338
vpn: VarType.VPN
337339
"""
338340
ICMP_TYPE = {4: {'echo-reply': 0,
@@ -458,6 +460,8 @@ def __init__(self, obj):
458460
self.encapsulate = None
459461
self.port_mirror = None
460462
# srx specific
463+
self.destination_zone = []
464+
self.source_zone = []
461465
self.vpn = None
462466
# gce specific
463467
self.source_tag = []
@@ -677,6 +681,14 @@ def __contains__(self, other):
677681
if sorted(self.platform_exclude) is not sorted(other.platform_exclude):
678682
return False
679683

684+
if self.source_zone:
685+
if sorted(self.source_zone) is not sorted(other.source_zone):
686+
return False
687+
688+
if self.destination_zone:
689+
if sorted(self.destination_zone) is not sorted(other.destination_zone):
690+
return False
691+
680692
# we have containment
681693
return True
682694

@@ -790,6 +802,10 @@ def __str__(self):
790802
(vpn_name, pair_policy))
791803
else:
792804
ret_str.append(' vpn: name = %s' % vpn_name)
805+
if self.source_zone:
806+
ret_str.append(' source_zone: %s' % sorted(self.source_zone))
807+
if self.destination_zone:
808+
ret_str.append(' destination_zone: %s' % sorted(self.destination_zone))
793809

794810
return '\n'.join(ret_str)
795811

@@ -937,6 +953,14 @@ def __eq__(self, other):
937953
if self.port_mirror != other.port_mirror:
938954
return False
939955

956+
# source_zone
957+
if sorted(self.source_zone) != sorted(other.source_zone):
958+
return False
959+
960+
# destination_zone
961+
if sorted(self.destination_zone) != sorted(other.destination_zone):
962+
return False
963+
940964
return True
941965

942966
def __ne__(self, other):
@@ -1137,6 +1161,10 @@ def AddObject(self, obj):
11371161
self.target_resources.append(x.value)
11381162
elif x.var_type is VarType.TARGET_SERVICE_ACCOUNTS:
11391163
self.target_service_accounts.append(x.value)
1164+
elif x.var_type is VarType.SZONE:
1165+
self.source_zone.append(x.value)
1166+
elif x.var_type is VarType.DZONE:
1167+
self.destination_zone.append(x.value)
11401168
else:
11411169
raise TermObjectTypeError(
11421170
'%s isn\'t a type I know how to deal with (contains \'%s\')' % (
@@ -1537,6 +1565,8 @@ class VarType:
15371565
FILTER_TERM = 62
15381566
RESTRICT_ADDRESS_FAMILY = 63
15391567
PORT_MIRROR = 64
1568+
SZONE = 65
1569+
DZONE = 66
15401570

15411571

15421572
def __init__(self, var_type, value):
@@ -1711,6 +1741,7 @@ def __ne__(self, other):
17111741
'DSCP_RANGE',
17121742
'DSCP_SET',
17131743
'DTAG',
1744+
'DZONE',
17141745
'ENCAPSULATE',
17151746
'ESCAPEDSTRING',
17161747
'ETHER_TYPE',
@@ -1758,6 +1789,7 @@ def __ne__(self, other):
17581789
'SPFX',
17591790
'ESPFX',
17601791
'SPORT',
1792+
'SZONE',
17611793
'STAG',
17621794
'STRING',
17631795
'TARGET',
@@ -1793,6 +1825,7 @@ def __ne__(self, other):
17931825
'destination-prefix-except': 'EDPFX',
17941826
'destination-port': 'DPORT',
17951827
'destination-tag': 'DTAG',
1828+
'destination-zone': 'DZONE',
17961829
'dscp-except': 'DSCP_EXCEPT',
17971830
'dscp-match': 'DSCP_MATCH',
17981831
'dscp-set': 'DSCP_SET',
@@ -1838,6 +1871,7 @@ def __ne__(self, other):
18381871
'source-prefix-except': 'ESPFX',
18391872
'source-port': 'SPORT',
18401873
'source-tag': 'STAG',
1874+
'source-zone': 'SZONE',
18411875
'target': 'TARGET',
18421876
'target-resources': 'TARGET_RESOURCES',
18431877
'target-service-accounts': 'TARGET_SERVICE_ACCOUNTS',
@@ -2011,6 +2045,7 @@ def p_term_spec(p):
20112045
| term_spec qos_spec
20122046
| term_spec pan_application_spec
20132047
| term_spec routinginstance_spec
2048+
| term_spec term_zone_spec
20142049
| term_spec tag_list_spec
20152050
| term_spec target_resources_spec
20162051
| term_spec target_service_accounts_spec
@@ -2365,6 +2400,15 @@ def p_verbatim_spec(p):
23652400
| VERBATIM ':' ':' STRING ESCAPEDSTRING """
23662401
p[0] = VarType(VarType.VERBATIM, [p[4], p[5].strip('"').replace('\\"', '"')])
23672402

2403+
def p_term_zone_spec(p):
2404+
""" term_zone_spec : SZONE ':' ':' one_or_more_strings
2405+
| DZONE ':' ':' one_or_more_strings """
2406+
p[0] = []
2407+
for zone in p[4]:
2408+
if p[1].find('source-zone') >= 0:
2409+
p[0].append(VarType(VarType.SZONE, zone))
2410+
elif p[1].find('destination-zone') >= 0:
2411+
p[0].append(VarType(VarType.DZONE, zone))
23682412

23692413
def p_vpn_spec(p):
23702414
""" vpn_spec : VPN ':' ':' STRING STRING

‎capirca/lib/policy_simple.py

+6
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ class DestinationPrefixExcept(Field):
169169
class DestinationTag(Field):
170170
"""A destination tag field."""
171171

172+
class DestinationZone(Field):
173+
"""A destination-zone field."""
172174

173175
class DscpMatch(Field):
174176
"""A dscp-match field."""
@@ -297,6 +299,8 @@ class SourcePrefixExcept(Field):
297299
class SourceTag(Field):
298300
"""A source tag field."""
299301

302+
class SourceZone(Field):
303+
"""A source-zone field."""
300304

301305
class Target(Field):
302306
"""A target field."""
@@ -337,6 +341,7 @@ class Vpn(Field):
337341
'destination-prefix': DestinationPrefix,
338342
'destination-prefix-except': DestinationPrefixExcept,
339343
'destination-tag': DestinationTag,
344+
'destination-zone': DestinationZone,
340345
'dscp-match': DscpMatch,
341346
'dscp-set': DscpSet,
342347
'ether-type': EtherType,
@@ -370,6 +375,7 @@ class Vpn(Field):
370375
'source-prefix': SourcePrefix,
371376
'source-prefix-except': SourcePrefixExcept,
372377
'source-tag': SourceTag,
378+
'source-zone': SourceZone,
373379
'target': Target,
374380
'timeout': Timeout,
375381
'traffic-class-count': TrafficClassCount,

‎doc/generators/junipersrx.md

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ target:: srx from-zone [zone name] to-zone [zone name] {inet}
1313
* _destination-address::_ One or more destination address tokens
1414
* _destination-exclude::_ Exclude one or more address tokens from the specified destination-address
1515
* _destination-port::_ One or more service definition tokens
16+
* _destination-zone::_ one or more destination zones tokens. Only supported by global policy
1617
* _dscp_except::_ Do not match the DSCP number.
1718
* _dscp_match::_ Match a DSCP number.
1819
* _dscp_set::_ Match a DSCP set.
@@ -36,6 +37,7 @@ target:: srx from-zone [zone name] to-zone [zone name] {inet}
3637
* _source-address::_ one or more source address tokens.
3738
* _source-exclude::_ exclude one or more address tokens from the specified source-address.
3839
* _source-port::_ one or more service definition tokens.
40+
* _source-zone::_ one or more source zones tokens. Only supported by global policy
3941
* _timeout::_ specify application timeout. (default 60)
4042
* _verbatim::_ this specifies that the text enclosed within quotes should be rendered into the output without interpretation or modification. This is sometimes used as a temporary workaround while new required features are being added.
4143
* _vpn::_ Encapsulate outgoing IP packets and decapsulate incomfing IP packets.

‎tests/lib/junipersrx_test.py

+27-2
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,16 @@
506506
}
507507
"""
508508

509+
GLOBAL_ZONE_TERM = """
510+
term global-zone-term {
511+
protocol:: icmp
512+
icmp-type:: echo-request
513+
source-zone:: szone2 szone1
514+
destination-zone:: dzone2 dzone1
515+
action:: accept
516+
}
517+
"""
518+
509519
PLATFORM_EXCLUDE_TERM = """
510520
term platform-exclude-term {
511521
protocol:: tcp udp
@@ -531,15 +541,17 @@
531541
}
532542
"""
533543

534-
SUPPORTED_TOKENS = {
544+
SUPPORTED_TOKENS = frozenset({
535545
'action',
536546
'comment',
537547
'destination_address',
538548
'destination_address_exclude',
539549
'destination_port',
550+
'destination_zone',
540551
'dscp_except',
541552
'dscp_match',
542553
'dscp_set',
554+
'source_zone',
543555
'expiration',
544556
'icmp_type',
545557
'stateless_reply',
@@ -557,7 +569,7 @@
557569
'translated',
558570
'verbatim',
559571
'vpn'
560-
}
572+
})
561573

562574
SUPPORTED_SUB_TOKENS = {
563575
'action': {'accept', 'deny', 'reject', 'count', 'log', 'dscp'},
@@ -911,6 +923,19 @@ def testTimeout(self):
911923
output = str(junipersrx.JuniperSRX(pol, EXP_INFO))
912924
self.assertIn('timeout 77', output, output)
913925

926+
def testZoneGlobal(self):
927+
pol = policy.ParsePolicy(GOOD_HEADER_10 + GLOBAL_ZONE_TERM, self.naming)
928+
output = str(junipersrx.JuniperSRX(pol, EXP_INFO))
929+
self.assertIn('from-zone', output, output)
930+
self.assertIn('szone1 szone2', output, output)
931+
self.assertIn('to-zone', output, output)
932+
self.assertIn('dzone1 dzone2', output, output)
933+
934+
def testZoneNonGlobal(self):
935+
pol = policy.ParsePolicy(GOOD_HEADER + GLOBAL_ZONE_TERM, self.naming)
936+
self.assertRaises(junipersrx.UnsupportedFilterError,
937+
junipersrx.JuniperSRX, pol, EXP_INFO)
938+
914939
def testIcmpV6(self):
915940
pol = policy.ParsePolicy(GOOD_HEADER + IPV6_ICMP_TERM, self.naming)
916941
output = str(junipersrx.JuniperSRX(pol, EXP_INFO))

‎tests/lib/policy_test.py

+17
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,14 @@
431431
port-mirror:: true
432432
}
433433
"""
434+
GOOD_TERM_48 = """
435+
term good-term-48 {
436+
protocol:: icmp
437+
source-zone:: zone1 zone2
438+
destination-zone:: zone1 zone2
439+
action:: accept
440+
}
441+
"""
434442
GOOD_TERM_V6_1 = """
435443
term good-term-v6-1 {
436444
hop-limit:: 5
@@ -1242,6 +1250,15 @@ def testPortMirror(self):
12421250
result = policy.ParsePolicy(pol, self.naming)
12431251
self.assertIn('port_mirror: true', str(result))
12441252

1253+
def testSrxGLobalZone(self):
1254+
pol = HEADER + GOOD_TERM_48
1255+
result = policy.ParsePolicy(pol, self.naming)
1256+
zones = ['zone1', 'zone2']
1257+
expected_source = 'source_zone: %s' % zones
1258+
expected_destination = 'destination_zone: %s' % zones
1259+
self.assertIn(expected_source, str(result))
1260+
self.assertIn(expected_destination, str(result))
1261+
12451262
def testTTL(self):
12461263
pol = HEADER + GOOD_TERM_43
12471264
result = policy.ParsePolicy(pol, self.naming)

0 commit comments

Comments
 (0)
Please sign in to comment.