def test_dynamic_source_nat(self): options = LogOptions() rule_values = {} nat = DynamicSourceNAT(options.data) nat.translated_value = '12.12.12.12' nat.translated_ports = (2000, 60000) rule_values.update(options=nat.data) self.assertEqual(nat.translated_value, '12.12.12.12') self.assertEqual(nat.translated_ports, (2000, 60000)) nat.translated_value = '13.13.13.13' nat.translated_ports = (1000, 10001) self.assertEqual(nat.translated_value, '13.13.13.13') self.assertEqual(nat.translated_ports, (1000, 10001)) self.assertIsNone(nat.original_value) options = LogOptions() host = Host('test', href='http://1.1.1.1') nat = DynamicSourceNAT(options.data) nat.translated_ports = (6000, 10000) nat.translated_value = host self.assertEqual(nat.translated_ports, (6000, 10000)) self.assertEqual(nat.translated_value, 'http://1.1.1.1') # Add bad host, translated value should not change with patch('smc.base.model.Element.href', new_callable=PropertyMock) as foo: foo.side_effect = ElementNotFound nat.translated_value = Host('foo') # Still original value self.assertEqual(nat.translated_value, 'http://1.1.1.1')
def test_automatic_proxy(self): options = LogOptions() nat = StaticDestNAT(options.data) self.assertIsNone(nat.automatic_proxy) # NAT is not yet configured nat.translated_value = '1.1.1.1' nat.automatic_proxy = True self.assertTrue(nat.automatic_proxy)
def options(self): """ Rule based options for logging. Enabling and disabled specific log settings. :rtype: LogOptions """ return LogOptions(self)
def test_static_dst_nat_add_translated_then_ports(self): options = LogOptions() nat = StaticDestNAT(options.data) nat.translated_value = '55.55.55.55' self.assertEqual(nat.translated_value, '55.55.55.55') nat.translated_ports = ('6005-6007', '8001-8002') self.assertEqual(nat.translated_value, '55.55.55.55') self.assertEqual(nat.translated_ports, ('6005-6007', '8001-8002'))
def options(self): """ Rule based options for logging. Enabling and disabled specific log settings. :return: :py:class:`smc.policy.rule_elements.LogOptions` """ return LogOptions(self.data.get('options'))
def test_static_dst_nat_add_ports_first(self): options = LogOptions() nat = StaticDestNAT(options.data) self.assertIsNone(nat.translated_ports) nat.translated_ports = (6000, 7000) self.assertEquals(nat.translated_ports, (6000, 7000)) nat.translated_value = 'http://1.1.1.1' self.assertEqual(nat.translated_ports, (6000, 7000)) self.assertEqual(nat.translated_value, 'http://1.1.1.1')
def test_static_dst_nat_add_translated_value_then_original(self): options = LogOptions() nat = StaticDestNAT(options.data) nat.translated_value = '2.2.2.2' self.assertEqual(nat.translated_value, '2.2.2.2') nat.original_value = 'http://1.1.1.1' self.assertEqual(nat.original_value, 'http://1.1.1.1') self.assertEqual(nat.translated_value, '2.2.2.2')
def create(self, name, sources=None, destinations=None, services=None, action='allow', is_disabled=False, vpn_policy=None, **kwargs): """ Create a layer 3 firewall rule :param str name: name of rule :param list source: source/s for rule, in href format :param list destination: destinations, in href format :param list service: service/s, in href format :param str action: allow|continue|discard|refuse|enforce_vpn|apply_vpn|blacklist (default: allow) :param str: vpn_policy: vpn policy name; required for enforce_vpn and apply_vpn actions :raises: :py:class:`smc.api.exceptions.MissingRequiredInput` when options are specified the need additional setting, i.e. use_vpn action requires a vpn policy be specified. :raises: :py:class:`smc.api.exceptions.CreateRuleFailed`: rule creation failure :return: str href: href of new rule """ rule_values = _rule_common(sources, destinations, services) rule_values.update(name=name) rule_action = Action(actions=self.actions) rule_action.action = action if rule_action.action in ['apply_vpn', 'enforce_vpn', 'forward_vpn']: if vpn_policy is None: raise MissingRequiredInput('A VPN policy must be specified when ' 'rule action has a VPN action') try: vpn = VPNPolicy(vpn_policy).href rule_action.vpn = vpn except ElementNotFound: raise MissingRequiredInput('Cannot find VPN policy specified: {}, ' .format(vpn_policy)) rule_values.update(rule_action()) log_options = LogOptions() auth_options = AuthenticationOptions() rule_values.update(log_options()) rule_values.update(auth_options()) rule_values.update(is_disabled=is_disabled) return prepared_request(CreateRuleFailed, href=self.href, json=rule_values).create().href
def test_static_dst_nat_add_original_value_then_translated(self): options = LogOptions() nat = StaticDestNAT(options.data) nat.original_value = 'http://1.1.1.1' self.assertEqual(nat.original_value, 'http://1.1.1.1') # Add translated value nat.translated_value = '2.2.2.2' self.assertEqual(nat.translated_value, '2.2.2.2') self.assertEqual(nat.translated_value, '2.2.2.2') self.assertEqual(nat.original_value, 'http://1.1.1.1') # Simulate SMC resolving translated value nat.data['static_dst_nat']['original_value'].update( {'ip_descriptor': '1.1.1.1'}) self.assertEqual(nat.original_value, '1.1.1.1')
def test_static_src_nat(self): options = LogOptions() nat = StaticSourceNAT(options.data) self.assertIsNone(nat.translated_value) self.assertIsNone(nat.original_value) # Original value as an element host = Host('test', href='http://1.1.1.1') nat.original_value = host # as element href self.assertEqual(nat.original_value, 'http://1.1.1.1') # Translated address as element href nat.translated_value = host self.assertEqual(nat.translated_value, 'http://1.1.1.1') # Specify IP for translated address nat.translated_value = '2.2.2.2' self.assertEqual(nat.translated_value, '2.2.2.2') # Incorrect format, needs to be href or element nat.original_value = '10.10.10.10' # same as original self.assertEqual(nat.original_value, 'http://1.1.1.1') nat.original_value = 'http://2.2.2.2' self.assertEqual(nat.original_value, 'http://2.2.2.2') with patch('smc.base.model.Element.href', new_callable=PropertyMock) as foo: foo.side_effect = ElementNotFound self.assertEqual(nat.translated_value, '2.2.2.2') # Before nat.translated_value = Host('foo') # Invalid host self.assertEqual(nat.translated_value, '2.2.2.2') # After self.assertEqual(nat.original_value, 'http://2.2.2.2') # Before nat.original_value = Host('foo') # Invalid host self.assertEqual(nat.original_value, 'http://2.2.2.2') # After
def test_automatic_proxy_added_first(self): options = LogOptions() nat = StaticDestNAT(options.data) nat.automatic_proxy = True self.assertTrue(nat.automatic_proxy)
def create(self, name, sources=None, destinations=None, services=None, dynamic_src_nat=None, dynamic_src_nat_ports=(1024, 65535), static_src_nat=None, static_dst_nat=None, static_dst_nat_ports=None, is_disabled=False, used_on=None): """ Create a NAT rule. When providing sources/destinations or services, you can provide the element href, network element or service from :py:class:`smc.elements.network` and :py:class:`smc.elements.service`. You can also use both types of input for these fields. :param str name: name of NAT rule :param list sources: list of sources by href or :py:class:`smc.elements.network` :param list destinations: list of destinations by href or :py:class:`smc.elements.network` :param list services: list of services by href or :py:class:`smc.elements.service` :param dynamic_src_nat: str ip or element from :py:class:`smc.elements.network` for dest NAT :param tuple dynamic_src_nat_ports: starting and ending ports for PAT. Default: (1024, 65535) :param static_src_nat: str ip or element href of used for source NAT :param static_dst_nat: destination NAT IP address or element href :param tuple static_dst_nat_ports: ports or port range used for original and destination ports (only needed if a different destination port is used and does not match the rules service port) :param boolean is_disabled: whether to disable rule or not :param str used_on: element or href (of security engine) where this NAT rule applies, Default: Any :raises: :py:class:`smc.api.exceptions.InvalidRuleValue`: if rule requirements are not met :raises: :py:class:`smc.api.exceptions.CreateRuleFailed`: rule creation failure :return: None """ rule_values = _rule_common(sources, destinations, services) rule_values.update(name=name) rule_values.update(is_disabled=is_disabled) options = LogOptions() if dynamic_src_nat: nat = DynamicSourceNAT(options.data) nat.translated_value = dynamic_src_nat nat.translated_ports = (dynamic_src_nat_ports) rule_values.update(options=nat.data) elif static_src_nat: nat = StaticSourceNAT(options.data) nat.translated_value = static_src_nat nat.original_value = sources[0].href rule_values.update(options=nat.data) if static_dst_nat: destination = Destination(rule_values['destinations']) if destination.is_any or destination.is_none: raise InvalidRuleValue( 'Destination field cannot be none or any for ' 'destination NAT.') nat = StaticDestNAT(options.data) nat.translated_value = static_dst_nat nat.original_value = destination.all_as_href()[0] rule_values.update(options=nat.data) if 'options' not in rule_values: # No NAT rule_values.update(options=options.data) rule_values.update(used_on=used_on) return prepared_request(CreateRuleFailed, href=self.href, json=rule_values).create()
def create(self, name, sources=None, destinations=None, services=None, action='allow', log_options=None, authentication_options=None, connection_tracking=None, is_disabled=False, vpn_policy=None, mobile_vpn=False, add_pos=None, after=None, before=None, sub_policy=None, comment=None, **kw): """ Create a layer 3 firewall rule :param str name: name of rule :param sources: source/s for rule :type sources: list[str, Element] :param destinations: destination/s for rule :type destinations: list[str, Element] :param services: service/s for rule :type services: list[str, Element] :param action: allow,continue,discard,refuse,enforce_vpn, apply_vpn,forward_vpn, blacklist (default: allow) :type action: Action or str :param LogOptions log_options: LogOptions object :param ConnectionTracking connection_tracking: custom connection tracking settings :param AuthenticationOptions authentication_options: options for auth if any :param PolicyVPN,str vpn_policy: policy element or str href; required for enforce_vpn, use_vpn and apply_vpn actions :param bool mobile_vpn: if using a vpn action, you can set mobile_vpn to True and omit the vpn_policy setting if you want this VPN to apply to any mobile VPN based on the policy VPN associated with the engine :param str,Element sub_policy: sub policy required when rule has an action of 'jump'. Can be the FirewallSubPolicy element or href. :param int add_pos: position to insert the rule, starting with position 1. If the position value is greater than the number of rules, the rule is inserted at the bottom. If add_pos is not provided, rule is inserted in position 1. Mutually exclusive with ``after`` and ``before`` params. :param str after: Rule tag to add this rule after. Mutually exclusive with ``add_pos`` and ``before`` params. :param str before: Rule tag to add this rule before. Mutually exclusive with ``add_pos`` and ``after`` params. :param str comment: optional comment for this rule :raises MissingRequiredInput: when options are specified the need additional setting, i.e. use_vpn action requires a vpn policy be specified. :raises CreateRuleFailed: rule creation failure :return: the created ipv4 rule :rtype: IPv4Rule """ rule_values = self.update_targets(sources, destinations, services) rule_values.update(name=name, comment=comment) if isinstance(action, Action): rule_action = action else: rule_action = Action() rule_action.action = action if not rule_action.action in self._actions: raise CreateRuleFailed('Action specified is not valid for this ' 'rule type; action: {}'.format( rule_action.action)) if rule_action.action in ('apply_vpn', 'enforce_vpn', 'forward_vpn'): if vpn_policy is None and not mobile_vpn: raise MissingRequiredInput( 'You must either specify a vpn_policy or set ' 'mobile_vpn when using a rule with a VPN action') if mobile_vpn: rule_action.mobile_vpn = True else: try: vpn = element_resolver(vpn_policy) # VPNPolicy rule_action.vpn = vpn except ElementNotFound: raise MissingRequiredInput( 'Cannot find VPN policy specified: {}, '.format( vpn_policy)) elif rule_action.action == 'jump': try: rule_action.sub_policy = element_resolver(sub_policy) except ElementNotFound: raise MissingRequiredInput( 'Cannot find sub policy specified: {} '.format(sub_policy)) #rule_values.update(action=rule_action.data) log_options = LogOptions() if not log_options else log_options if connection_tracking is not None: rule_action.connection_tracking_options.update( **connection_tracking) auth_options = AuthenticationOptions() if not authentication_options \ else authentication_options rule_values.update(action=rule_action.data, options=log_options.data, authentication_options=auth_options.data, is_disabled=is_disabled) params = None href = self.href if add_pos is not None: href = self.add_at_position(add_pos) elif before or after: params = self.add_before_after(before, after) return ElementCreator(self.__class__, exception=CreateRuleFailed, href=href, params=params, json=rule_values)
def add_policy(self): """ If a client AMI was specified when building a new VPC, this will add rules to allow inbound access to the AMI. This could be extended to more generically support VPN rules. """ if not self.firewall_policy: self.firewall_policy = 'AWS_Default' # Policy not specified, use the default, or check if hidden setting was specified try: FirewallPolicy.create(name='AWS_Default', template='Firewall Inspection Template') except CreatePolicyFailed: pass # Already exists policy = FirewallPolicy(self.firewall_policy) # Create the access rule for the network options = LogOptions() options.log_accounting_info_mode = True options.log_level = 'stored' options.application_logging = 'enforced' options.user_logging = 'enforced' action = Action() action.deep_inspection = True action.file_filtering = False outbound_rule = policy.search_rule('AWS outbound access rule') if not outbound_rule: # Generic outbound access rule policy.fw_ipv4_access_rules.create( name='AWS outbound access rule', sources=[Alias('$$ Interface ID 1.net')], destinations='any', services='any', action=action, log_options=options) if self.aws_ami_ip and self.nat_ports: dest_port = self.nat_ports.get('dest_port') redirect_port = self.nat_ports.get('redirect_port') services = list( TCPService.objects.filter(dest_port)) # @UndefinedVariable # Ignore services with protocol agents so we skip SSM service = next( ([service] for service in services if not service.protocol_agent), []) if not service: service = [ TCPService.create(name='aws_tcp{}'.format(dest_port), min_dst_port=dest_port) ] # Create the access rule for the client policy.fw_ipv4_access_rules.create( name=self.name, sources='any', destinations=[Alias('$$ Interface ID 0.ip')], services=service, action='allow', log_options=options) policy.fw_ipv4_nat_rules.create( name=self.name, sources='any', destinations=[Alias('$$ Interface ID 0.ip')], services=service, static_dst_nat=self.aws_ami_ip, static_dst_nat_ports=(dest_port, redirect_port), used_on=self.engine.href)
def __init__(self, rule=None): options = LogOptions().data if not rule else rule.data.get("options") self.rule = rule super(NATElement, self).__init__(data=options)
def create(self, name, sources=None, destinations=None, services=None, action="allow", log_options=None, authentication_options=None, match_vpn_options=None, connection_tracking=None, is_disabled=False, vpn_policy=None, mobile_vpn=False, add_pos=None, after=None, before=None, sub_policy=None, comment=None, validate=True, **kw): """ Create a layer 3 firewall rule .. versionchanged:: 0.7.0 Action field now requires a list of actions as strings when using SMC version >= 6.6.0 :param str name: name of rule :param sources: source/s for rule :type sources: list[str, Element] :param destinations: destination/s for rule :type destinations: list[str, Element] :param services: service/s for rule :type services: list[str, Element] :param action: allow,continue,discard,refuse,enforce_vpn, apply_vpn,forward_vpn, blacklist (default: allow) :type action: Action,str,list[str] :param LogOptions log_options: LogOptions object :param ConnectionTracking connection_tracking: custom connection tracking settings :param AuthenticationOptions authentication_options: options for auth if any :param SourceVpn match_vpn_options: rule matches traffic from specific VPNs :param PolicyVPN,str vpn_policy: policy element or str href; required for enforce_vpn, use_vpn and apply_vpn actions :param bool mobile_vpn: if using a vpn action, you can set mobile_vpn to True and omit the vpn_policy setting if you want this VPN to apply to any mobile VPN based on the policy VPN associated with the engine :param str,Element sub_policy: sub policy required when rule has an action of 'jump'. Can be the FirewallSubPolicy element or href. :param int add_pos: position to insert the rule, starting with position 1. If the position value is greater than the number of rules, the rule is inserted at the bottom. If add_pos is not provided, rule is inserted in position 1. Mutually exclusive with ``after`` and ``before`` params. :param str after: Rule tag to add this rule after. Mutually exclusive with ``add_pos`` and ``before`` params. :param str before: Rule tag to add this rule before. Mutually exclusive with ``add_pos`` and ``after`` params. :param str comment: optional comment for this rule :param bool validate: validate the inspection policy during rule creation. Default: True :raises MissingRequiredInput: when options are specified the need additional setting, i.e. use_vpn action requires a vpn policy be specified. :raises CreateRuleFailed: rule creation failure :return: the created ipv4 rule :rtype: IPv4Rule """ rule_values = self.update_targets(sources, destinations, services) rule_action = self._get_action(action) if any(vpn in rule_action.action for vpn in ("apply_vpn", "enforce_vpn", "forward_vpn")): if vpn_policy is None and not mobile_vpn: raise MissingRequiredInput( "You must either specify a vpn_policy or set " "mobile_vpn when using a rule with a VPN action") if mobile_vpn: rule_action.mobile_vpn = True else: try: vpn = element_resolver(vpn_policy) # VPNPolicy rule_action.vpn = vpn except ElementNotFound: raise MissingRequiredInput( "Cannot find VPN policy specified: {}, ".format( vpn_policy)) elif "jump" in rule_action.action: try: rule_action.sub_policy = element_resolver(sub_policy) except ElementNotFound: raise MissingRequiredInput( "Cannot find sub policy specified: {} ".format(sub_policy)) log_options = LogOptions() if not log_options else log_options if connection_tracking is not None: rule_action.connection_tracking_options.update( **connection_tracking) auth_options = (AuthenticationOptions() if not authentication_options else authentication_options) match_vpn_data = None if not match_vpn_options else match_vpn_options.data rule_values.update(name=name, comment=comment, action=rule_action.data, options=log_options.data, authentication_options=auth_options.data, match_vpn_options=match_vpn_data, is_disabled=is_disabled, **kw) params = {"validate": False} if not validate else {} href = self.href if add_pos is not None: href = self.add_at_position(add_pos) elif before or after: params.update(**self.add_before_after(before, after)) return ElementCreator(self.__class__, exception=CreateRuleFailed, href=href, params=params, json=rule_values)
def test_log_options(self): options = LogOptions() options.log_accounting_info_mode = False options.log_level = 'stored' options.application_logging = 'enforced' options.user_logging = 'enforced' options.comment = 'my new comment!!' options.log_closing_mode = True options.log_level = 'transient' options.log_payload_additional = True options.log_payload_excerpt = True options.log_payload_record = True self.assertTrue(options.log_accounting_info_mode) self.assertTrue(options.log_closing_mode) self.assertEqual(options.log_level, 'transient') self.assertTrue(options.log_payload_additional) self.assertTrue(options.log_payload_excerpt) self.assertTrue(options.log_payload_record) self.assertEqual(options.user_logging, 'enforced') self.assertEqual(options.log_severity, -1) self.assertEqual(options.application_logging, 'enforced') o = options() for k, v in o.items(): self.assertEqual(k, 'options') self.assertDictEqual(v, options.data)
def exec_module(self, **kwargs): state = kwargs.pop('state', 'present') for name, value in kwargs.items(): setattr(self, name, value) changed = False try: # Now that we have valid option settings, we can hit the db if self.policy: policy = FirewallPolicy.get(self.policy) else: policy = FirewallSubPolicy.get(self.sub_policy) if state == 'present': for rule in self.rules: try: validate_rule_syntax(rule) except Exception as e: self.fail(msg=str(e)) self.cache = Cache() for rule in self.rules: # Resolve elements if they exist, calls to SMC could happen here if 'sources' in rule: self.field_resolver(rule.get('sources'), rule_targets) if 'destinations' in rule: self.field_resolver(rule.get('destinations'), rule_targets) if 'services' in rule: self.field_resolver(rule.get('services'), service_targets) if 'vpn_policy' in rule: self.cache._add_entry('vpn', rule.get('vpn_policy')) if 'sub_policy' in rule: self.cache._add_entry('sub_ipv4_fw_policy', rule.get('sub_policy')) if 'authentication_options' in rule: auth = rule['authentication_options'] if auth.get('require_auth'): for method in auth.get('methods'): self.cache._add_entry('authentication_service', method) for accounts in ('users', 'groups'): self.cache._add_user_entries(accounts, auth.get(accounts, [])) if self.cache.missing: self.fail(msg='Missing required elements that are referenced in this ' 'configuration: %s' % self.cache.missing) if self.check_mode: return self.results for rule in self.rules: rule_dict = {} if 'log_options' in rule: log_options = LogOptions() _log = rule['log_options'] for name, value in log_options.items(): if name not in _log: log_options.pop(name) log_options.update(rule.get('log_options', {})) rule_dict.update(log_options=log_options) if 'connection_tracking' in rule: connection_tracking = ConnectionTracking() _ct = rule['connection_tracking'] for name, value in connection_tracking.items(): if name not in _ct: connection_tracking.pop(name) connection_tracking.update(rule.get('connection_tracking',{})) rule_dict.update(connection_tracking=connection_tracking) action = Action() # If no action, set to default based on version if 'action' not in rule: action.action = 'allow' if not is_sixdotsix_compat() else ['allow'] else: action.action = rule.get('action') if 'inspection_options' in rule: _inspection = rule['inspection_options'] for option in inspection_options: if option in _inspection: action[option] = _inspection.get(option) if 'authentication_options' in rule: _auth_options = rule['authentication_options'] auth_options = AuthenticationOptions() if _auth_options.get('require_auth'): auth_options.update(methods=[ self.get_value('authentication_service', m).href for m in _auth_options.get('methods', [])], require_auth=True) auth_options.update(users=[entry.href for entry in self.cache.get_type('user_element')]) rule_dict.update(authentication_options=auth_options) rule_dict.update(action=action) for field in ('sources', 'destinations', 'services'): rule_dict[field] = self.get_values(rule.get(field, None)) rule_dict.update( vpn_policy=self.get_value('vpn', rule.get('vpn_policy')), sub_policy=self.get_value('sub_ipv4_fw_policy', rule.get('sub_policy')), mobile_vpn=rule.get('mobile_vpn', False)) if 'comment' in rule: rule_dict.update(comment=rule.get('comment')) rule_dict.update( name=rule.get('name'), is_disabled=rule.get('is_disabled', False)) if 'tag' not in rule: # If no tag is present, this is a create rule_dict.update( before=rule.get('add_before'), after=rule.get('add_after')) rule = policy.fw_ipv4_access_rules.create(**rule_dict) changed = True self.results['state'].append({ 'rule': rule.name, 'type': rule.typeof, 'action': 'created'}) else: # Modify as rule has 'tag' defined. Fetch the rule first # by it's tag reference, skip if tag not found target_rule = self.rule_by_tag(policy, rule.get('tag')) if not target_rule: continue changes = compare_rules(target_rule, rule_dict) # Changes have already been merged if any if rule.get('add_after', None): rule_at_pos = self.rule_by_tag(policy, rule.get('add_after')) if rule_at_pos: target_rule.move_rule_after(rule_at_pos) changes.append('add_after') elif rule.get('add_before', None): rule_at_pos = self.rule_by_tag(policy, rule.get('add_before')) if rule_at_pos: target_rule.move_rule_before(rule_at_pos) changes.append('add_before') elif changes: target_rule.save() if changes: changed = True self.results['state'].append({ 'rule': target_rule.name, 'type': target_rule.typeof, 'action': 'modified', 'changes': changes}) elif state == 'absent': for rule in self.rules: if 'tag' in rule: target_rule = self.rule_by_tag(policy, rule.get('tag')) if target_rule: target_rule.delete() changed = True self.results['state'].append({ 'rule': target_rule.name, 'type': target_rule.typeof, 'action': 'deleted'}) except SMCException as err: self.fail(msg=str(err), exception=traceback.format_exc()) self.results['changed'] = changed return self.results
def create(self, name, sources=None, destinations=None, services=None, dynamic_src_nat=None, dynamic_src_nat_ports=(1024, 65535), static_src_nat=None, static_dst_nat=None, static_dst_nat_ports=None, is_disabled=False, used_on=None): """ Create a NAT rule. When providing sources/destinations or services, you can provide the element href, network element or services from ``smc.elements``. You can also mix href strings with Element types in these fields. :param str name: name of NAT rule :param list sources: list of sources by href or Element :type sources: list(str,Element) :param list destinations: list of destinations by href or Element :type destinations: list(str,Element) :param list services: list of services by href or Element :type services: list(str,Element) :param dynamic_src_nat: str ip or Element for dest NAT :type dynamic_src_nat: str,Element :param tuple dynamic_src_nat_ports: starting and ending ports for PAT. Default: (1024, 65535) :param str static_src_nat: ip or element href of used for source NAT :param str static_dst_nat: destination NAT IP address or element href :param tuple static_dst_nat_ports: ports or port range used for original and destination ports (only needed if a different destination port is used and does not match the rules service port) :param bool is_disabled: whether to disable rule or not :param str used_on: href or Element (of security engine) where this NAT rule applies, Default: Any :type used_on: str,Element :raises InvalidRuleValue: if rule requirements are not met :raises CreateRuleFailed: rule creation failure :return: newly created NAT rule :rtype: IPv4NATRule """ rule_values = self.update_targets(sources, destinations, services) rule_values.update(name=name) rule_values.update(is_disabled=is_disabled) options = LogOptions() if dynamic_src_nat: nat = DynamicSourceNAT(options.data) nat.translated_value = dynamic_src_nat nat.translated_ports = (dynamic_src_nat_ports) rule_values.update(options=nat.data) elif static_src_nat: nat = StaticSourceNAT(options.data) nat.translated_value = static_src_nat nat.original_value = sources[0].href rule_values.update(options=nat.data) if static_dst_nat: destinations = rule_values['destinations'] if 'any' in destinations or 'none' in destinations: raise InvalidRuleValue( 'Destination field cannot be none or any for ' 'destination NAT.') destination = Destination() destination.add_many(destinations.get('dst')) nat = StaticDestNAT(options.data) nat.translated_value = static_dst_nat nat.original_value = destination.all_as_href()[0] if static_dst_nat_ports: nat.translated_ports = static_dst_nat_ports rule_values.update(options=nat.data) if 'options' not in rule_values: # No NAT rule_values.update(options=options.data) rule_values.update(used_on=used_on) return SubElementCreator(self.__class__, CreateRuleFailed, href=self.href, json=rule_values)
def create( self, name, sources=None, destinations=None, services=None, dynamic_src_nat=None, dynamic_src_nat_ports=(1024, 65535), static_src_nat=None, static_dst_nat=None, static_dst_nat_ports=None, is_disabled=False, used_on="ANY", add_pos=None, after=None, before=None, comment=None, validate=True, ): """ Create a NAT rule. When providing sources/destinations or services, you can provide the element href, network element or services from ``smc.elements``. You can also mix href strings with Element types in these fields. :param str name: name of NAT rule :param list sources: list of sources by href or Element :type sources: list(str,Element) :param list destinations: list of destinations by href or Element :type destinations: list(str,Element) :param list services: list of services by href or Element :type services: list(str,Element) :param dynamic_src_nat: str ip or Element for dest NAT :type dynamic_src_nat: str,Element :param tuple dynamic_src_nat_ports: starting and ending ports for PAT. Default: (1024, 65535) :param str static_src_nat: ip or element href of used for source NAT :param str static_dst_nat: destination NAT IP address or element href :param tuple static_dst_nat_ports: ports or port range used for original and destination ports (only needed if a different destination port is used and does not match the rules service port) :param bool is_disabled: whether to disable rule or not :param str,Engine used_on: Can be None, 'ANY' or and Engine element. Default is 'ANY'. :type used_on: str,Element :param int add_pos: position to insert the rule, starting with position 1. If the position value is greater than the number of rules, the rule is inserted at the bottom. If add_pos is not provided, rule is inserted in position 1. Mutually exclusive with ``after`` and ``before`` params. :param str after: Rule tag to add this rule after. Mutually exclusive with ``add_pos`` and ``before`` params. :param str before: Rule tag to add this rule before. Mutually exclusive with ``add_pos`` and ``after`` params. :param str comment: optional comment for the NAT rule :param bool validate: validate the inspection policy during rule creation. Default: True :raises InvalidRuleValue: if rule requirements are not met :raises CreateRuleFailed: rule creation failure :return: newly created NAT rule :rtype: IPv4NATRule """ rule_values = self.update_targets(sources, destinations, services) rule_values.update(name=name, comment=comment, is_disabled=is_disabled) rule_values.update(used_on={"any": True} if used_on == "ANY" else element_resolver(used_on)) if dynamic_src_nat: nat = DynamicSourceNAT() start_port, end_port = dynamic_src_nat_ports nat.update_field(dynamic_src_nat, start_port=start_port, end_port=end_port) rule_values.update(options=nat) elif static_src_nat: sources = rule_values["sources"] if "any" in sources or "none" in sources: raise InvalidRuleValue( "Source field cannot be none or any for " "static source NAT.") nat = StaticSourceNAT() nat.update_field(static_src_nat, original_value=sources.get("src")[0]) rule_values.update(options=nat) if static_dst_nat: destinations = rule_values["destinations"] if "any" in destinations or "none" in destinations: raise InvalidRuleValue( "Destination field cannot be none or any for " "destination NAT.") nat = StaticDestNAT() original_port, translated_port = None, None if static_dst_nat_ports: original_port, translated_port = static_dst_nat_ports nat.update_field( static_dst_nat, original_value=destinations.get("dst")[0], original_port=original_port, translated_port=translated_port, ) rule_values.setdefault("options", {}).update(nat) if "options" not in rule_values: # No NAT rule_values.update(options=LogOptions()) params = {"validate": False} if not validate else {} href = self.href if add_pos is not None: href = self.add_at_position(add_pos) elif before or after: params.update(**self.add_before_after(before, after)) return ElementCreator(self.__class__, exception=CreateRuleFailed, href=href, params=params, json=rule_values)
def create(self, name, sources=None, destinations=None, services=None, action='allow', log_options=None, is_disabled=False, vpn_policy=None, add_pos=None, after=None, before=None, sub_policy=None, comment=None, **kw): """ Create a layer 3 firewall rule :param str name: name of rule :param sources: source/s for rule :type sources: list[str, Element] :param destinations: destination/s for rule :type destinations: list[str, Element] :param services: service/s for rule :type services: list[str, Element] :param action: allow,continue,discard,refuse,enforce_vpn, apply_vpn,blacklist (default: allow) :type action: Action or str :param LogOptions log_options: LogOptions object :param str: vpn_policy: vpn policy name; required for enforce_vpn and apply_vpn actions :param str,Element sub_policy: sub policy required when rule has an action of 'jump'. Can be the FirewallSubPolicy element or href. :param int add_pos: position to insert the rule, starting with position 1. If the position value is greater than the number of rules, the rule is inserted at the bottom. If add_pos is not provided, rule is inserted in position 1. Mutually exclusive with ``after`` and ``before`` params. :param str after: Rule tag to add this rule after. Mutually exclusive with ``add_pos`` and ``before`` params. :param str before: Rule tag to add this rule before. Mutually exclusive with ``add_pos`` and ``after`` params. :param str comment: optional comment for this rule :raises MissingRequiredInput: when options are specified the need additional setting, i.e. use_vpn action requires a vpn policy be specified. :raises CreateRuleFailed: rule creation failure :return: the created ipv4 rule :rtype: IPv4Rule """ rule_values = self.update_targets(sources, destinations, services) rule_values.update(name=name, comment=comment) if isinstance(action, Action): rule_action = action else: rule_action = Action() rule_action.action = action if not rule_action.action in self._actions: raise CreateRuleFailed('Action specified is not valid for this ' 'rule type; action: {}'.format( rule_action.action)) if rule_action.action in ['apply_vpn', 'enforce_vpn', 'forward_vpn']: if vpn_policy is None: raise MissingRequiredInput( 'A VPN policy must be specified when ' 'rule action has a VPN action') try: vpn = PolicyVPN(vpn_policy).href rule_action.vpn = vpn except ElementNotFound: raise MissingRequiredInput( 'Cannot find VPN policy specified: {}, '.format( vpn_policy)) elif rule_action.action in ['jump']: try: rule_action.sub_policy = element_resolver(sub_policy) except ElementNotFound: raise MissingRequiredInput( 'Cannot find sub policy specified: {} '.format(sub_policy)) rule_values.update(action=rule_action.data) if log_options is None: log_options = LogOptions() auth_options = AuthenticationOptions() rule_values.update(options=log_options.data) rule_values.update(authentication_options=auth_options.data) rule_values.update(is_disabled=is_disabled) params = None href = self.href if add_pos is not None: href = self.add_at_position(add_pos) elif before or after: params = self.add_before_after(before, after) return SubElementCreator(self.__class__, CreateRuleFailed, href=href, params=params, json=rule_values)