Beispiel #1
0
 def make_acl(self,
              acl_name,
              target_url,
              protocol,
              match_type,
              direction_initiated,
              local_ports=None,
              remote_ports=None):
     # (acl_name, protocol_direction, ip_version, target_url, protocol, match_type,
     #           direction_initiated, local_ports=None, remote_ports=None):
     if "v4" in acl_name:
         ip_version = IPVersion.IPV4
     elif "v6" in acl_name:
         ip_version = IPVersion.IPV6
     else:
         raise InputException("Invalid IPVersion provided")
     acl_type_prefix = get_ipversion_string(ip_version)
     if acl_name.endswith("to"):
         protocol_direction = Direction.TO_DEVICE
     elif acl_name.endswith("fr"):
         protocol_direction = Direction.FROM_DEVICE
     else:
         raise InputException("Invalid Direction provided")
     return {
         'name': acl_name,
         'type': acl_type_prefix + '-acl-type',
         'aces': {
             'ace':
             self.make_ace(protocol_direction, target_url, protocol,
                           match_type, direction_initiated, ip_version,
                           local_ports, remote_ports)
         }
     }
Beispiel #2
0
def make_acldns_match(domain: str, direction: Direction):
    """Function to generate an ACL match for a domain.

    Args:
        domain (str): The domain for this ACL
        direction (Direction): The direction for which the TCP connection was initiated.
                               `Direction.TO_DEVICE` for source domain, `Direction.FROM_DEVICE`
                               for destination domain.

    Returns:
        dict: A dictionary representing the ACLDNS match.

    """
    # TODO: (1/4) Readdress the regex override (mostly for testing)
    if not re.match(DOMAIN_NAME_REGEX, domain) and not REGEX_OVERRIDE:
        raise InputException(f"Not a domain name: {domain}")

    acldns_match = {}
    key = "ietf-acldns:src-dnsname" if direction is Direction.TO_DEVICE else \
        "ietf-acldns:dst-dnsname" if direction is Direction.FROM_DEVICE else None

    if key:
        acldns_match[key] = domain
    else:
        raise InputException(f"direction is not valid: {direction}")

    return acldns_match
Beispiel #3
0
    def add_rule(self,
                 target_url: str,
                 protocol: Protocol,
                 match_type: str,
                 direction_initiated: Direction = None,
                 local_port: int = None,
                 remote_port: int = None):
        if len(target_url) > 140:
            raise InputException('target url is too long: {}' % target_url)
        match = {}

        if match_type is MatchType.IS_LOCAL:
            match['ietf-mud:mud'] = make_local_match()
            self.rules_local.append(match)
        elif match_type is MatchType.IS_CLOUD:
            match['target_url'] = target_url
            self.rules_cloud.append(match)
        elif match_type is MatchType.IS_CONTROLLER:
            match['ietf-mud:mud'] = make_controller_match(target_url)
            self.rules_controller.append(match)
        elif match_type is MatchType.IS_MY_CONTROLLER:
            match['ietf-mud:mud'] = make_my_controller_match()
            self.rules_controller_my.append(match)
        elif match_type is MatchType.IS_MFG:
            match['ietf-mud:mud'] = make_manufacturer_match(target_url)
            self.rules_manufacturer.append(match)
        elif match_type is MatchType.IS_MYMFG:
            match['ietf-mud:mud'] = make_same_manufacturer_match()
            self.rules_manufacturer_my.append(match)

        if match.get('ietf-mud:mud') is None and match.get(
                'target_url') is None:
            raise InputException(f"match_type is not valid: {match_type}")

        match['protocol'] = protocol
        if protocol is not Protocol.ANY:
            match['remote_port'] = remote_port
            match['local_port'] = local_port

            if protocol is Protocol.TCP:
                match["cloud_placeholder"] = {'protocol': 6}
                #match['tcp'] = True
                match['direction_initiated'] = direction_initiated
            elif protocol is Protocol.UDP:
                match["cloud_placeholder"] = {'protocol': 17}
            else:
                raise InputException(f'protocol is not valid: {protocol}')
        return
Beispiel #4
0
 def make_acls(self,
               ip_version,
               target_url,
               protocol,
               match_types,
               direction_initiated,
               local_ports=None,
               remote_ports=None,
               acl_names=None,
               mud_name=None):
     acls = {}
     if acl_names is None and mud_name is None:
         raise InputException(
             'acl_names and mud_name can\'t both by None at the same time')
     elif acl_names is None:
         acl_names = self.make_acl_names(mud_name, ip_version,
                                         direction_initiated)
     if ip_version == [IPVersion.BOTH]:
         ip_version = [IPVersion.IPV4, IPVersion.IPV6]
     for i in range(len(acl_names)):
         for protocol_direction in [
                 Direction.TO_DEVICE, Direction.FROM_DEVICE
         ]:
             acls.update(
                 self.make_acl(protocol_direction, ip_version[i],
                               target_url, protocol, match_types,
                               direction_initiated, local_ports,
                               remote_ports, acl_names[i]))
     return acls
Beispiel #5
0
def get_protocol_direction_suffix_string(direction):
    if direction is Direction.TO_DEVICE:
        return 'to'
    if direction is Direction.FROM_DEVICE:
        return 'fr'

    raise InputException(f'protocol_direction is not valid: {direction}')
Beispiel #6
0
def make_acl(protocol_direction,
             ip_version,
             target_url,
             protocol,
             match_types,
             direction_initiated,
             local_ports=None,
             remote_ports=None,
             acl_name=None,
             mud_name=None):
    acl_type_prefix = get_ipversion_string(ip_version)
    if acl_name is None and mud_name is None:
        raise InputException(
            'acl_name and mud_name can\'t both by None at the same time')
    elif acl_name is None:
        acl_name = make_acl_name(mud_name, ip_version, direction_initiated)
    return {
        'name': acl_name,
        'type': acl_type_prefix + '-acl-type',
        'aces': {
            'ace':
            make_ace(protocol_direction, target_url, protocol, match_types,
                     direction_initiated, ip_version, local_ports,
                     remote_ports)
        }
    }
Beispiel #7
0
def get_ipversion_string(ip_version):
    if ip_version is IPVersion.IPV4:
        return 'ipv4'
    if ip_version is IPVersion.IPV6:
        return 'ipv6'

    raise InputException(f'ip_version is not valid: {ip_version}')
Beispiel #8
0
def get_policy_type_prefix_string(direction):
    if direction is Direction.TO_DEVICE:
        return 'to'
    elif direction is Direction.FROM_DEVICE:
        return 'from'

    raise InputException(f'direction is not valid: {direction}')
Beispiel #9
0
def get_protocol_object(protocol):
    if protocol == 'udp':
        return Protocol.UDP
    if protocol == 'tcp':
        return Protocol.TCP
    if protocol == 'any':
        return Protocol.ANY
    raise InputException(f'protocol is not valid: {protocol}')
Beispiel #10
0
def get_ipversion_object(ip_version):
    if ip_version == 'ipv4':
        return IPVersion.IPV4
    if ip_version == 'ipv6':
        return IPVersion.IPV4
    if ip_version == 'both':
        return IPVersion.BOTH
    raise InputException(f'ip_version is not valid: {ip_version}')
Beispiel #11
0
def get_match_type_object(match_type):
    if match_type == 'is_my_controller':
        return MatchType.IS_MY_CONTROLLER
    if match_type == 'is_controller':
        return MatchType.IS_CONTROLLER
    if match_type == 'is_mfg':
        return MatchType.IS_MFG
    if match_type == 'is_mymfg':
        return MatchType.IS_MYMFG
    if match_type == 'is_cloud':
        return MatchType.IS_CLOUD
    raise InputException(f'match_type is not valid: {match_type}')
Beispiel #12
0
def get_ace_name(match_type):
    if match_type is MatchType.IS_LOCAL:
        return 'loc'
    if match_type is MatchType.IS_CLOUD:
        return 'cl'
    if match_type is MatchType.IS_MYMFG:
        return 'myman'
    if match_type is MatchType.IS_MFG:
        return 'man'
    if match_type is MatchType.IS_MY_CONTROLLER:
        return 'myctl'
    if match_type is MatchType.IS_CONTROLLER:
        return 'ent'

    raise InputException(f'match_type is not valid: {match_type}')
Beispiel #13
0
def make_manufacturer_match(domain: str):
    """Function to generate an ACL match for access to named manufacturers of devices that
       are identified by the domain names in their MUD URLs

    Args:
        domain (str): domain name for manufacturer

    Returns:
        dict: A dictionary representing the manufacturer match.

    """
    # TODO: (3/4) Readdress the regex override (mostly for testing)
    if not re.match(DOMAIN_NAME_REGEX, domain) and not REGEX_OVERRIDE:
        raise InputException("Not a domain name: {domain}")

    return {'manufacturer': domain}
Beispiel #14
0
def make_controller_match(url: str):
    """Function to generate an ACL match for classes of devices that are known to be controllers

    Args:
        url (str): URI for the device class

    Returns:
        dict: A dictionary representing the controller match.

    """
    # TODO: (2/4) Readdress the regex override (mostly for testing)
    if not (re.match(HTTP_URL_REGEX, url)
            or re.match(URN_URL_REGEX, url)) and not REGEX_OVERRIDE:
        raise InputException('Not a valid URI: {}' % url)

    return {'controller': url}
Beispiel #15
0
def get_direction_object(direction):
    if direction == 'to_device':
        return Direction.TO_DEVICE
    if direction == 'from_device':
        return Direction.FROM_DEVICE
    raise InputException(f'direction is not valid: {direction}')
Beispiel #16
0
def get_sub_ace_name(ace_name, direction, sub_ace_number):
    if direction is Direction.TO_DEVICE:
        return f"{ace_name}{sub_ace_number}-todev"
    if direction is Direction.FROM_DEVICE:
        return f"{ace_name}{sub_ace_number}-frdev"
    raise InputException(f'direction is not valid: {direction}')
Beispiel #17
0
    def make_mud_5(self):
        #mud = self.support_info
        #mud.update(self.policies)
        #self.mud_file = {'ietf-mud:mud': mud, 'ietf-access-control-list:acls': {'acl': self.acls}}
        #return self.mud_file

        #def assemble_mud(self):

        if self.ip_version == IPVersion.BOTH:
            ip_version = [IPVersion.IPV4, IPVersion.IPV6]
            self.acl = [
                self.acl_v4_to, self.acl_v4_from, self.acl_v6_to,
                self.acl_v6_from
            ]
        else:
            ip_version = [self.ip_version]
            if self.ip_version == IPVersion.IPV4:
                #self.acl_v4_to = {}
                #self.acl_v4_from = {}
                self.acl = [self.acl_v4_to, self.acl_v4_from]
            elif self.ip_version == IPVersion.IPV6:
                #self.acl_v6_to = {}
                #self.acl_v6_from = {}
                self.acl = [self.acl_v6_to, self.acl_v6_from]

        rule_list = [(MatchType.IS_LOCAL, self.rules_local),
                     (MatchType.IS_CLOUD, self.rules_cloud),
                     (MatchType.IS_CONTROLLER, self.rules_controller),
                     (MatchType.IS_MY_CONTROLLER, self.rules_controller_my),
                     (MatchType.IS_MFG, self.rules_manufacturer),
                     (MatchType.IS_MYMFG, self.rules_manufacturer_my)]

        # Not the most efficient way to do this, but it works
        for (i, (match_type, rules)) in enumerate(rule_list):
            for (j, rule) in enumerate(rules):
                for protocol_direction in [
                        Direction.TO_DEVICE, Direction.FROM_DEVICE
                ]:
                    for ipv in ip_version:
                        sub_ace_name = get_sub_ace_name(
                            get_ace_name(match_type), protocol_direction, j)
                        match = {}
                        ip_version_string = get_ipversion_string(ipv)
                        source_port = None
                        destination_port = None
                        direction_initiated = rule.get('direction_initiated')

                        if rule.get('ietf-mud:mud') is not None:
                            match['ietf-mud:mud'] = rule['ietf-mud:mud']
                            cloud_entry = None
                        else:
                            cloud_entry = make_acldns_match(
                                rule['target_url'], protocol_direction)

                        if rule['protocol'] is Protocol.ANY:
                            if cloud_entry:
                                match[ip_version_string] = cloud_entry
                        else:
                            if protocol_direction is Direction.FROM_DEVICE:
                                source_port = rule.get('remote_port')
                                destination_port = rule.get('local_port')
                            elif protocol_direction is Direction.TO_DEVICE:
                                source_port = rule.get('local_port')
                                destination_port = rule.get('remote_port')
                            if rule['protocol'] is Protocol.TCP:
                                match[ip_version_string] = rule.get(
                                    "cloud_placeholder").copy(
                                    )  # {'protocol': 6}
                                if source_port is not None or destination_port is not None or \
                                        direction_initiated is not None:
                                    match['tcp'] = make_port_range(
                                        direction_initiated, source_port,
                                        destination_port)
                            elif rule['protocol'] is Protocol.UDP:
                                match[ip_version_string] = rule.get(
                                    "cloud_placeholder").copy(
                                    )  # {'protocol': 17}
                                if rule.get(
                                        'source_port') is not None or rule.get(
                                            'destination_port') is not None:
                                    match['udp'] = make_port_range(
                                        dir_init=None,
                                        source_port=source_port,
                                        destination_port=destination_port)
                            else:
                                raise InputException(
                                    f'protocol is not valid: {rule["protocol"]}'
                                )
                            if cloud_entry:
                                match[ip_version_string].update(cloud_entry)

                        ace = {
                            'name': sub_ace_name,
                            'matches': match,
                            'actions': {
                                'forwarding': 'accept'
                            }
                        }

                        if ipv == IPVersion.IPV4:
                            if protocol_direction == Direction.TO_DEVICE:
                                self.acl_v4_to['aces']['ace'].append(ace)
                                #self.acl.append(self.acl_v4_to.copy())
                            else:
                                self.acl_v4_from['aces']['ace'].append(ace)
                                #self.acl.append(self.acl_v4_from.copy())
                        elif ipv == IPVersion.IPV6:
                            if protocol_direction == Direction.TO_DEVICE:
                                self.acl_v6_to['aces']['ace'].append(ace)
                                #self.acl.append(self.acl_v6_to.copy())
                            else:
                                self.acl_v6_from['aces']['ace'].append(ace)
                                #self.acl.append(self.acl_v6_from.copy())

        mud = self.support_info
        mud.update(self.policies)
        self.mud_file = {
            'ietf-mud:mud': mud,
            'ietf-access-control-list:acls': {
                'acl': self.acl
            }
        }
        return self.mud_file
Beispiel #18
0
    def make_sub_ace(self,
                     sub_ace_name,
                     protocol_direction,
                     target_url,
                     protocol,
                     match_type,
                     direction_initiated,
                     ip_version,
                     local_port=None,
                     remote_port=None):
        if len(target_url) > 140:
            raise InputException('target url is too long: {}' % target_url)
        match = {}

        ip_version = get_ipversion_string(ip_version)
        source_port = None
        destination_port = None
        cloud_ipv4_entry = None

        if match_type is MatchType.IS_LOCAL:
            match['ietf-mud:mud'] = make_local_match()
        elif match_type is MatchType.IS_CLOUD:
            cloud_ipv4_entry = make_acldns_match(target_url,
                                                 protocol_direction)
        elif match_type is MatchType.IS_CONTROLLER:
            match['ietf-mud:mud'] = make_controller_match(target_url)
        elif match_type is MatchType.IS_MY_CONTROLLER:
            match['ietf-mud:mud'] = make_my_controller_match()
        elif match_type is MatchType.IS_MFG:
            match['ietf-mud:mud'] = make_manufacturer_match(target_url)
        elif match_type is MatchType.IS_MYMFG:
            match['ietf-mud:mud'] = make_same_manufacturer_match()

        if match.get('ietf-mud:mud') is None and cloud_ipv4_entry is None:
            raise InputException(f"match_type is not valid: {match_type}")

        if protocol is Protocol.ANY:
            if cloud_ipv4_entry:
                match[ip_version] = cloud_ipv4_entry
        else:
            if protocol_direction is Direction.FROM_DEVICE:
                source_port = remote_port
                destination_port = local_port
            elif protocol_direction is Direction.TO_DEVICE:
                source_port = local_port
                destination_port = remote_port
            if protocol is Protocol.TCP:
                match[ip_version] = {'protocol': 6}
                if source_port is not None or destination_port is not None or direction_initiated is not None:
                    match['tcp'] = make_port_range(direction_initiated,
                                                   source_port,
                                                   destination_port)
            elif protocol is Protocol.UDP:
                match[ip_version] = {'protocol': 17}
                if source_port is not None or destination_port is not None:
                    match['udp'] = make_port_range(source_port,
                                                   destination_port)
            else:
                raise InputException(f'protocol is not valid: {protocol}')
            if cloud_ipv4_entry:
                match[ip_version].update(cloud_ipv4_entry)
        return {
            'name': sub_ace_name,
            'matches': match,
            'actions': {
                'forwarding': 'accept'
            }
        }