コード例 #1
0
    def _do_mod(self, ipaddr, port, proto, tcpmss, tcpsack, tcpwscale):
        # Modify a connection based on given parameters
        # Define inserting position based on n-tuple match
        if ipaddr != '0.0.0.0' and port != 0:
            # 3-tuple connection, higher priority
            pos = 1
        elif ipaddr != '0.0.0.0' and port == 0:
            # 3-tuple connection with wildcard port, higher priority than default
            pos = -3
        elif ipaddr == '0.0.0.0':
            # Default connection, lowest priority
            pos = -2
        else:
            raise Exception('Unsupported! {}'.format(ipaddr, proto, port,
                                                     tcpmss, tcpsack,
                                                     tcpwscale))

        if self.connectiontable.has((ipaddr, port, proto)):
            connection = self.connectiontable.get((ipaddr, port, proto))
            # Check if the existing parameters are the same
            if connection.tcpmss == tcpmss and connection.tcpsack == tcpsack and connection.tcpwscale == tcpwscale:
                self._logger.debug(
                    '[mod] Modify not required : {} / {}'.format(
                        connection, (tcpmss, tcpsack, tcpwscale)))
                return True
            # Create iptables rule and update connection object
            old_ipt_rule = connection.ipt_rule
            new_ipt_rule = self._build_ipt_synproxy_rule(
                ipaddr, port, proto, tcpmss, tcpsack, tcpwscale)
            self._logger.info('Modify connection: {} / {}'.format(
                connection, (tcpmss, tcpsack, tcpwscale)))
            connection.ipt_rule = new_ipt_rule
            # Replace rule
            iptc_helper3.replace_rule('filter',
                                      'synproxy_chain',
                                      old_ipt_rule,
                                      new_ipt_rule,
                                      ipv6=False)
        else:
            # Create iptables rule and connection object
            ipt_rule = self._build_ipt_synproxy_rule(ipaddr, port, proto,
                                                     tcpmss, tcpsack,
                                                     tcpwscale)
            connection = SYNProxyConnectionTCP(ipaddr, port, proto, tcpmss,
                                               tcpsack, tcpwscale, ipt_rule)
            self.connectiontable.add(connection)
            # Insert rule at precise position
            self._logger.info('Add connection: {}'.format(connection))
            iptc_helper3.add_rule('filter',
                                  'synproxy_chain',
                                  ipt_rule,
                                  position=pos,
                                  ipv6=False)

        return True
    def _generic_setup_provisioning(self, population, depth, token):
        '''
        Recursive function to walk tree structure for given depth and population, use carry-me-token for inner leafs
        Use token = ''   for building next level keys based on iterative concatenation of index keys
        Use token = None for building next level keys based on local index keys
        '''
        assert (depth >= 0)
        # Generate chain name based on tree position
        for table in ['raw', 'filter']:
            chain = self._whoami(table, token)
            iptc_helper3.add_chain(table, chain, ipv6=False, silent=False)
            iptc_helper3.flush_chain(table, chain, ipv6=False, silent=False)
            self.logger.debug('create&flush {}.{}'.format(table, chain))
            # Add records to classifier for fast indexing
            if depth == 0:
                self.provisioning_d[table][token] = chain

        if depth == 0:
            return

        # Walk towards each child, on return, link to them from the present chain
        for child in population:
            # Black magic for carry-me-token
            if token is not None:
                child = token_child = '{}{}'.format(
                    token, child)  # Recalculate new token and use as local key
            else:
                token_child = token  # Carry same token to next level

            # Execute function for each children, before walking
            pass
            # Walk child
            self._generic_setup_provisioning(population, depth - 1,
                                             token_child)
            # Execute function for each children, after walking
            for table in ['raw', 'filter']:
                chain = self._whoami(table, token)
                target_chain = self._whoami(table, token_child)
                classify_rule = {
                    'in-interface': 'qbr{}+'.format(token_child),
                    'target': target_chain
                }
                self.logger.debug('add_rule / @{} {}'.format(
                    chain, classify_rule))
                iptc_helper3.add_rule(table, chain, classify_rule, ipv6=False)
コード例 #3
0
    def _do_add(self, ipaddr, port, proto, tcpmss, tcpsack, tcpwscale):
        # Add a connection based on given parameters
        # Define inserting position based on n-tuple match
        if ipaddr != '0.0.0.0' and port != 0:
            # 3-tuple connection, higher priority
            pos = 1
        elif ipaddr != '0.0.0.0' and port == 0:
            # 3-tuple connection with wildcard port, higher priority than default
            pos = -3
        elif ipaddr == '0.0.0.0':
            # Default connection, lowest priority
            pos = -2
        else:
            raise Exception('Unsupported! {}'.format(ipaddr, proto, port,
                                                     tcpmss, tcpsack,
                                                     tcpwscale))

        if self.connectiontable.has((ipaddr, port, proto)):
            connection = self.connectiontable.get((ipaddr, port, proto))
            self._logger.debug('[add] Conflict exists for {} / {}'.format(
                (ipaddr, port, proto, tcpmss, tcpsack, tcpwscale), connection))
            return False

        # Create iptables rule and connection object
        ipt_rule = self._build_ipt_synproxy_rule(ipaddr, port, proto, tcpmss,
                                                 tcpsack, tcpwscale)
        connection = SYNProxyConnectionTCP(ipaddr, port, proto, tcpmss,
                                           tcpsack, tcpwscale, ipt_rule)
        self.connectiontable.add(connection)
        # Insert rule at precise position
        self._logger.info('Add connection: {}'.format(connection))
        iptc_helper3.add_rule('filter',
                              'synproxy_chain',
                              ipt_rule,
                              position=pos,
                              ipv6=False)
        return True
 def setup_provisioning(self):
     self.logger.info('Installing common provisioning')
     # Store key value of classifying uuid to chain, for each table
     self.provisioning_d = {'raw': {}, 'filter': {}}
     # Generate population base
     self.population = self._generate_population_base(
         self.args.classify_base)
     # Do custom provisioning based on optimization model
     self.logger.info('Installing optimization specific provisioning')
     self._generic_setup_provisioning(self.population,
                                      self.args.classify_level, '')
     # Insert hooks in raw and filter tables
     rule = {'in-interface': 'qbr+', 'target': CUSTOM_RAW_PRE}
     iptc_helper3.add_rule('raw',
                           NEUTRON_RAW_PRE_HOOK,
                           rule,
                           NEUTRON_RAW_PRE_HOOK_i,
                           ipv6=False)
     rule = {'in-interface': 'qbr+', 'target': CUSTOM_FILTER_FWD}
     iptc_helper3.add_rule('filter',
                           NEUTRON_FILTER_FWD_HOOK,
                           rule,
                           NEUTRON_FILTER_FWD_HOOK_i,
                           ipv6=False)
コード例 #5
0
    def ipt_init_flows(self):
        # Specific TCP flows are inserted/appended to filter.synproxy_chain """
        self._logger.info('Initialize iptables chains and rules')

        # Add custom chains
        iptc_helper3.add_chain('raw',
                               'synproxy_chain',
                               ipv6=False,
                               silent=True)
        iptc_helper3.add_chain('filter',
                               'synproxy_chain',
                               ipv6=False,
                               silent=True)

        # Flush chains
        iptc_helper3.flush_chain('raw', 'PREROUTING', ipv6=False, silent=False)
        iptc_helper3.flush_chain('filter', 'FORWARD', ipv6=False, silent=False)
        iptc_helper3.flush_chain('raw',
                                 'synproxy_chain',
                                 ipv6=False,
                                 silent=False)
        iptc_helper3.flush_chain('filter',
                                 'synproxy_chain',
                                 ipv6=False,
                                 silent=False)

        # Populate chains with basic rules
        ## raw.PREROUTING
        ### Add a rate limitation to raw.PREROUTING via hashlimit module
        _above = '{}/sec'.format(self.ratelimit[0])
        _burst = '{}'.format(self.ratelimit[1])
        rule_d = {
            'in-interface': 'mitm0',
            'protocol': 'tcp',
            'tcp': {
                'tcp-flags': ['FIN,SYN,RST,ACK', 'SYN']
            },
            'target': 'DROP',
            'hashlimit': {
                'hashlimit-above': _above,
                'hashlimit-burst': _burst,
                'hashlimit-name': 'internet_syn',
                'hashlimit-mode': 'srcip',
                'hashlimit-htable-size': '2097152',
                'hashlimit-srcmask': '24',
                'hashlimit-htable-expire': '1001'
            }
        }
        iptc_helper3.add_rule('raw',
                              'PREROUTING',
                              rule_d,
                              position=0,
                              ipv6=False)
        ###
        rule_d = {
            'in-interface': 'mitm0',
            'protocol': 'tcp',
            'target': 'synproxy_chain'
        }
        iptc_helper3.add_rule('raw',
                              'PREROUTING',
                              rule_d,
                              position=0,
                              ipv6=False)
        rule_d = {
            'in-interface': 'mitm1',
            'protocol': 'tcp',
            'target': 'synproxy_chain'
        }
        iptc_helper3.add_rule('raw',
                              'PREROUTING',
                              rule_d,
                              position=0,
                              ipv6=False)
        ## raw.synproxy_chain
        rule_d = {
            'in-interface': 'mitm0',
            'protocol': 'tcp',
            'tcp': {
                'tcp-flags': ['FIN,SYN,RST,ACK', 'SYN']
            },
            'target': {
                'CT': {
                    'notrack': ''
                }
            },
        }
        iptc_helper3.add_rule('raw',
                              'synproxy_chain',
                              rule_d,
                              position=0,
                              ipv6=False)
        rule_d = {'target': 'ACCEPT'}
        iptc_helper3.add_rule('raw',
                              'synproxy_chain',
                              rule_d,
                              position=0,
                              ipv6=False)
        ## filter.FORWARD
        rule_d = {
            'in-interface': 'mitm0',
            'protocol': 'tcp',
            'target': 'synproxy_chain'
        }
        iptc_helper3.add_rule('filter',
                              'FORWARD',
                              rule_d,
                              position=0,
                              ipv6=False)
        rule_d = {
            'in-interface': 'mitm1',
            'protocol': 'tcp',
            'target': 'synproxy_chain'
        }
        iptc_helper3.add_rule('filter',
                              'FORWARD',
                              rule_d,
                              position=0,
                              ipv6=False)
        ## filter.synproxy_chain
        rule_d = {
            'protocol': 'tcp',
            'conntrack': {
                'ctstate': ['INVALID']
            },
            'target': 'DROP'
        }
        iptc_helper3.add_rule('filter',
                              'synproxy_chain',
                              rule_d,
                              position=0,
                              ipv6=False)
    def _apply_optimized_rules(self, default, optimized):
        ''' Receives dicts of (uuid, rule) and applies diff following simple optimization '''
        # Calculate new sets for added & removed
        default_s = set(default.keys())
        optimized_s = set(optimized.keys())
        removed_s = optimized_s - default_s
        added_s = default_s - optimized_s

        if removed_s:
            self.logger.info('>> Remove old VM(s)! {}'.format(removed_s))
        if added_s:
            self.logger.info('>> Add new VM(s)! {}'.format(added_s))

        # Remove old entries
        for i, _uuid in enumerate(removed_s):
            self.logger.info('>> [#{}] Removing VM {}'.format(i + 1, _uuid))
            vm_chain = GENERATE_VM_CHAIN_NAME(_uuid)
            _rule = optimized[_uuid]
            # Iterate insertion tables and do cleanup
            for table in ['raw', 'filter']:
                cl_chain = self._lookup_chain_by_uuid(table, _uuid)
                if not cl_chain:
                    self.logger.critical('UUID {} not found in base {}'.format(
                        _uuid, self.args.classify_base))
                    continue
                # Delete trigger rule from classifying chain
                self.logger.debug('>>> delete rule: {}.{} {}'.format(
                    table, cl_chain, _rule))
                iptc_helper3.delete_rule(table, cl_chain, _rule, ipv6=False)
                # Delete VM optimized chain
                self.logger.debug('>>> flush & delete chain: {}.{}'.format(
                    table, vm_chain))
                iptc_helper3.flush_chain(table, vm_chain, ipv6=False)
                iptc_helper3.delete_chain(table, vm_chain, ipv6=False)

        # Add new entries
        for i, _uuid in enumerate(added_s):
            self.logger.info('>> [#{}] Adding VM {}'.format(i + 1, _uuid))
            vm_chain = GENERATE_VM_CHAIN_NAME(_uuid)

            ### RAW TABLE ###
            # Select classifying table to insert triggers
            table = 'raw'
            cl_chain = self._lookup_chain_by_uuid(table, _uuid)
            if not cl_chain:
                self.logger.critical('UUID {} not found in base {}'.format(
                    _uuid, self.args.classify_base))
                continue
            self.logger.debug('Selected classifying chain {}'.format(cl_chain))
            ## Create & populate VM optimized chain with simplest rules
            self.logger.debug('>>> add chain: {}.{}'.format(table, vm_chain))
            iptc_helper3.add_chain(table, vm_chain, ipv6=False)
            _rule = dict(default[_uuid])
            if 'physdev' in _rule:
                del _rule['physdev']
            if 'in-interface' in _rule:
                del _rule['in-interface']
            iptc_helper3.add_rule(table, vm_chain, _rule, ipv6=False)
            _rule = {
                'comment': {
                    'comment': 'Accept early'
                },
                'target': 'ACCEPT'
            }
            iptc_helper3.add_rule(table, vm_chain, _rule, ipv6=False)

            ## Add trigger rule to classifying chain
            _rule = dict(default[_uuid])
            if 'physdev' in _rule:
                del _rule['physdev']
            _rule['in-interface'] = 'qbr{}'.format(_uuid)
            _rule['target'] = vm_chain
            self.logger.debug('>>> add rule: {}.{} {}'.format(
                table, cl_chain, _rule))
            iptc_helper3.add_rule(table, cl_chain, _rule, ipv6=False)

            ### FILTER TABLE ###
            # Select classifying table to insert triggers
            table = 'filter'
            cl_chain = self._lookup_chain_by_uuid(table, _uuid)
            if not cl_chain:
                self.logger.critical('UUID {} not found in base {}'.format(
                    _uuid, self.args.classify_base))
                continue
            self.logger.debug('Selected classifying chain {}'.format(cl_chain))
            ## Create & populate VM optimized chain with simplest rules
            self.logger.debug('>>> add chain: {}.{}'.format(table, vm_chain))
            iptc_helper3.add_chain(table, vm_chain, ipv6=False)
            _rule = {
                'comment': {
                    'comment': 'Jump to the VM specific chain.'
                },
                'physdev': {
                    'physdev-is-bridged': [],
                    'physdev-in': 'tap{}'.format(_uuid)
                },
                'target': GEN_NEUTRON_SG_EGRESS(_uuid)
            }
            iptc_helper3.add_rule(table, vm_chain, _rule, ipv6=False)
            _rule = {
                'comment': {
                    'comment': 'Jump to the VM specific chain.'
                },
                'physdev': {
                    'physdev-is-bridged': '',
                    'physdev-out': 'tap{}'.format(_uuid)
                },
                'target': GEN_NEUTRON_SG_INGRESS(_uuid)
            }
            iptc_helper3.add_rule(table, vm_chain, _rule, ipv6=False)
            _rule = {
                'comment': {
                    'comment': 'Accept early'
                },
                'target': 'ACCEPT'
            }
            iptc_helper3.add_rule(table, vm_chain, _rule, ipv6=False)

            ## Add trigger rule to classifying chain
            _rule = dict(default[_uuid])
            if 'physdev' in _rule:
                del _rule['physdev']
            _rule['in-interface'] = 'qbr{}'.format(_uuid)
            _rule['target'] = vm_chain
            self.logger.debug('>>> add rule: {}.{} {}'.format(
                table, cl_chain, _rule))
            iptc_helper3.add_rule(table, cl_chain, _rule, ipv6=False)

        # Return number of optimizations performed
        return len(added_s)