From a33c44a0f85f7bd9028576635b0250934885440d Mon Sep 17 00:00:00 2001 From: Nathan Ward Date: Sat, 10 Sep 2022 16:25:56 +1200 Subject: [PATCH] Add ttl-except to juniper --- capirca/lib/juniper.py | 10 ++++++++-- capirca/lib/policy.py | 23 ++++++++++++++++++++++- doc/generators/juniper.md | 1 + tests/lib/juniper_test.py | 19 +++++++++++++++++++ tests/lib/policy_test.py | 22 ++++++++++++++++++++++ tests/lib/srxlo_test.py | 1 + 6 files changed, 73 insertions(+), 3 deletions(-) diff --git a/capirca/lib/juniper.py b/capirca/lib/juniper.py index 21a6d39a..575984f7 100644 --- a/capirca/lib/juniper.py +++ b/capirca/lib/juniper.py @@ -323,7 +323,8 @@ def __str__(self): self.term.source_prefix or self.term.source_prefix_except or self.term.traffic_type or - self.term.ttl) + self.term.ttl or + self.term.ttl_except) if has_match_criteria: config.Append('from {') @@ -452,6 +453,10 @@ def __str__(self): if self.term.ttl and self.term_type == 'inet': config.Append('ttl %s;' % self.term.ttl) + # ttl-except, same logic as ttl above. + if self.term.ttl_except and self.term_type == 'inet': + config.Append('ttl-except %s;' % self.term.ttl_except) + # protocol if self.term.protocol: # both are supported on JunOS, but only icmp6 is supported @@ -923,7 +928,8 @@ def _BuildTokens(self): 'source_prefix_except', 'traffic_type', 'traffic_class_count', - 'ttl'} + 'ttl', + 'ttl_except'} supported_sub_tokens.update({ 'option': { 'established', diff --git a/capirca/lib/policy.py b/capirca/lib/policy.py index 35981a31..47cddd36 100644 --- a/capirca/lib/policy.py +++ b/capirca/lib/policy.py @@ -438,6 +438,7 @@ def __init__(self, obj): self.source_port = [] self.source_prefix = [] self.ttl = None + self.ttl_except = None self.verbatim = [] # juniper specific. self.packet_length = None @@ -793,6 +794,8 @@ def __str__(self): ret_str.append(' platform_exclude: %s' % self.platform_exclude) if self.ttl: ret_str.append(' ttl: %s' % self.ttl) + if self.ttl_except: + ret_str.append(' ttl_except: %s' % self.ttl_except) if self.timeout: ret_str.append(' timeout: %s' % self.timeout) if self.vpn: @@ -884,6 +887,9 @@ def __eq__(self, other): if self.ttl != other.ttl: return False + if self.ttl_except != other.ttl_except: + return False + if sorted(self.logging) != sorted(other.logging): return False if self.log_limit != other.log_limit: @@ -1246,6 +1252,8 @@ def AddObject(self, obj): self.vpn = (obj.value[0], obj.value[1]) elif obj.var_type is VarType.TTL: self.ttl = int(obj.value) + elif obj.var_type is VarType.TTL_EXCEPT: + self.ttl_except = int(obj.value) elif obj.var_type is VarType.TARGET_RESOURCES: self.target_resources.append(obj.value) elif obj.var_type is VarType.TARGET_SERVICE_ACCOUNTS: @@ -1351,6 +1359,12 @@ def SanityCheck(self): raise InvalidTermTTLValue('Term %s contains invalid TTL: %s' % (self.name, self.ttl)) + if self.ttl_except: + if not _MIN_TTL <= self.ttl_except <= _MAX_TTL: + + raise InvalidTermTTLValue('Term %s contains invalid TTL: %s' + % (self.name, self.ttl_except)) + def AddressCleanup(self, optimize=True, addressbook=False): """Do Address and Port collapsing. @@ -1567,7 +1581,7 @@ class VarType: PORT_MIRROR = 64 SZONE = 65 DZONE = 66 - + TTL_EXCEPT = 67 def __init__(self, var_type, value): self.var_type = var_type @@ -1800,6 +1814,7 @@ def __ne__(self, other): 'TRAFFIC_CLASS_COUNT', 'TRAFFIC_TYPE', 'TTL', + 'TTL_EXCEPT', 'VERBATIM', 'VPN', ) @@ -1880,6 +1895,7 @@ def __ne__(self, other): 'traffic-class-count': 'TRAFFIC_CLASS_COUNT', 'traffic-type': 'TRAFFIC_TYPE', 'ttl': 'TTL', + 'ttl-except': 'TTL_EXCEPT', 'verbatim': 'VERBATIM', 'vpn': 'VPN', } @@ -2051,6 +2067,7 @@ def p_term_spec(p): | term_spec target_service_accounts_spec | term_spec timeout_spec | term_spec ttl_spec + | term_spec ttl_except_spec | term_spec traffic_type_spec | term_spec verbatim_spec | term_spec vpn_spec @@ -2475,6 +2492,10 @@ def p_ttl_spec(p): """ ttl_spec : TTL ':' ':' INTEGER """ p[0] = VarType(VarType.TTL, p[4]) +def p_ttl_except_spec(p): + """ ttl_except_spec : TTL_EXCEPT ':' ':' INTEGER """ + p[0] = VarType(VarType.TTL_EXCEPT, p[4]) + def p_filter_term_spec(p): """ filter_term_spec : FILTER_TERM ':' ':' STRING """ p[0] = VarType(VarType.FILTER_TERM, p[4]) diff --git a/doc/generators/juniper.md b/doc/generators/juniper.md index 764d15f3..abc4b405 100644 --- a/doc/generators/juniper.md +++ b/doc/generators/juniper.md @@ -81,6 +81,7 @@ The default format is _inet4_, and is implied if not other argument is given. * _traffic-class-count::_ * _traffic-type::_ specify traffic-type * _ttl::_ Matches on TTL. +* _ttl-except::_ Allow all TTL "except" specified. * _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. ## Sub Tokens ### Actions diff --git a/tests/lib/juniper_test.py b/tests/lib/juniper_test.py index def1bddf..022ef0d9 100644 --- a/tests/lib/juniper_test.py +++ b/tests/lib/juniper_test.py @@ -392,6 +392,12 @@ action:: accept } """ +GOOD_TERM_38 = """ +term good-term-38 { + ttl-except:: 10 + action:: accept +} +""" GOOD_TERM_COMMENT = """ term good-term-comment { comment:: "This is a COMMENT" @@ -645,6 +651,7 @@ 'traffic_type', 'translated', 'ttl', + 'ttl_except', 'verbatim']) SUPPORTED_SUB_TOKENS = { @@ -1504,12 +1511,24 @@ def testTTL(self): output = str(jcl) self.assertIn('ttl 10;', output) + def testTTLExcept(self): + jcl = juniper.Juniper(policy.ParsePolicy(GOOD_HEADER + GOOD_TERM_38, + self.naming), EXP_INFO) + output = str(jcl) + self.assertIn('ttl-except 10;', output) + def testTTLInet6(self): jcl = juniper.Juniper(policy.ParsePolicy(GOOD_HEADER_V6 + GOOD_TERM_21, self.naming), EXP_INFO) output = str(jcl) self.assertNotIn('ttl 10;', output) + def testTTLExceptInet6(self): + jcl = juniper.Juniper(policy.ParsePolicy(GOOD_HEADER_V6 + GOOD_TERM_38, + self.naming), EXP_INFO) + output = str(jcl) + self.assertNotIn('ttl-except 10;', output) + def testNextIpFormat(self): self.naming.GetNetAddr.return_value = [nacaddr.IP('10.1.1.1/32')] diff --git a/tests/lib/policy_test.py b/tests/lib/policy_test.py index 51f2a557..5fd4d0eb 100644 --- a/tests/lib/policy_test.py +++ b/tests/lib/policy_test.py @@ -439,6 +439,12 @@ action:: accept } """ +GOOD_TERM_49 = """ +term good-term-59 { + ttl-except:: 10 + action:: accept +} +""" GOOD_TERM_V6_1 = """ term good-term-v6-1 { hop-limit:: 5 @@ -584,6 +590,12 @@ action:: accept } """ +BAD_TERM_17 = """ +term bad-term-17 { + ttl-except:: 257 + action:: accept +} +""" # pylint: disable=maybe-no-member @@ -1269,6 +1281,16 @@ def testInvalidTTL(self): self.assertRaises(policy.InvalidTermTTLValue, policy.ParsePolicy, pol, self.naming) + def testTTLExcept(self): + pol = HEADER + GOOD_TERM_49 + result = policy.ParsePolicy(pol, self.naming) + self.assertIn('ttl_except: 10', str(result)) + + def testInvalidTTLExcept(self): + pol = HEADER + BAD_TERM_17 + self.assertRaises(policy.InvalidTermTTLValue, policy.ParsePolicy, + pol, self.naming) + def testNeedAddressBook(self): pol1 = policy.ParsePolicy(HEADER + GOOD_TERM_1, self.naming) pol2 = policy.ParsePolicy(HEADER_SRX + GOOD_TERM_1, self.naming) diff --git a/tests/lib/srxlo_test.py b/tests/lib/srxlo_test.py index 341b8e13..e88d7ee3 100644 --- a/tests/lib/srxlo_test.py +++ b/tests/lib/srxlo_test.py @@ -122,6 +122,7 @@ 'traffic_type', 'translated', 'ttl', + 'ttl_except', 'verbatim', }