示例#1
0
def _apply_policy(policy, devname, devaddr):
    """Create network interfaces, routes and firewall rules per policy.

    :param `str` devname:
        Local device name to use for the tunnel.
    :param `str` devaddr:
        IP address to use on the local device for the tunnel.
    """
    tun_devname = _utils.wg_dev_create(
        unique_id=policy['session_id'],
        tun_localaddr=policy['local_ip'],
        tun_remoteaddr=policy['remote_ip'],
        ll_devname=devname,
        ll_localaddr=devaddr,
        ll_remoteaddr=policy['endpoint_ip'],
    )
    # Add firewall rules.
    _utils.wg_firewall_client_init(tun_devname, policy['endpoints'])
    # No traffic should be *routed* from the WarpGate interface.
    netdev.dev_conf_forwarding_set(tun_devname, False)
    # Bring up the device.
    netdev.link_set_up(tun_devname)
    # Add routes found in the policy
    _utils.wg_route_create(
        tun_devname,
        policy['local_ip'],
        policy['remote_ip'],
        policy['routes']
    )
示例#2
0
    def on_create_request(self, rsrc_id, rsrc_data):
        """
        :returns ``dict``:
            Network IP `vip`, network device `veth`, IP gateway `gateway`.
        """
        with lc.LogContext(_LOGGER, rsrc_id,
                           adapter_cls=lc.ContainerAdapter) as log:
            log.debug('req: %r', rsrc_data)

            app_unique_name = rsrc_id
            environment = rsrc_data['environment']

            assert environment in _SET_BY_ENVIRONMENT, \
                'Unknown environment: %r' % environment

            veth0, veth1 = _device_from_rsrc_id(app_unique_name)

            if app_unique_name not in self._devices:
                # VIPs allocation (the owner is the resource link)
                ip = self._vips.alloc(rsrc_id)
                self._devices[app_unique_name] = {'ip': ip}
            else:
                # Re-read what IP we assigned before
                ip = self._devices[app_unique_name]['ip']

            if 'device' not in self._devices[app_unique_name]:
                # Create the interface pair
                netdev.link_add_veth(veth0, veth1)
                # Configure the links
                netdev.link_set_mtu(veth0, self.ext_mtu)
                netdev.link_set_mtu(veth1, self.ext_mtu)
                # Tag the interfaces
                netdev.link_set_alias(veth0, rsrc_id)
                netdev.link_set_alias(veth1, rsrc_id)
                # Add interface to the bridge
                netdev.bridge_addif(self._TMBR_DEV, veth0)
                netdev.link_set_up(veth0)
                # We keep veth1 down until inside the container

            # Record the new device in our state
            self._devices[app_unique_name] = _device_info(veth0)
            self._devices[app_unique_name].update({
                'ip': ip,
                'environment': environment,
            })

            # We can now mark ip traffic as belonging to the requested
            # environment.
            _add_mark_rule(ip, environment)

        result = {
            'vip': ip,
            'veth': veth1,
            'gateway': self._TM_IP,
            'external_ip': self.ext_ip,
        }
        return result
示例#3
0
    def test_link_set_up(self):
        """Test of device up."""
        netdev.link_set_up('foo')

        treadmill.subproc.check_call.assert_called_with([
            'ip',
            'link',
            'set',
            'dev',
            'foo',
            'up',
        ], )
示例#4
0
    def initialize(self, service_dir):
        super(NetworkResourceService, self).initialize(service_dir)
        # The <svcroot>/vips directory is used to allocate/de-allocate
        # container vips.
        vips_dir = os.path.join(service_dir, self._VIPS_DIR)
        # Initialize vips
        self._vips = vipfile.VipMgr(vips_dir, self._service_rsrc_dir)

        # Clear all environment assignments here. They will be re-assigned
        # below.
        for containers_set in set(_SET_BY_ENVIRONMENT.values()):
            iptables.create_set(containers_set,
                                set_type='hash:ip',
                                family='inet',
                                hashsize=1024,
                                maxelem=65536)

        need_init = False
        try:
            netdev.link_set_up(self._TM_DEV0)
            netdev.link_set_up(self._TM_DEV1)
            netdev.link_set_up(self._TMBR_DEV)

        except subproc.CalledProcessError:
            need_init = True

        if need_init:
            # Reset the bridge
            self._bridge_initialize()

        # These two are also done here because they are idempotent
        # Disable bridge forward delay
        netdev.bridge_setfd(self._TMBR_DEV, 0)
        # Enable route_localnet so that we can redirect traffic from the
        # container to the node's loopback address.
        netdev.dev_conf_route_localnet_set(self._TM_DEV0, True)

        # Read bridge status
        self._bridge_mtu = netdev.dev_mtu(self._TMBR_DEV)

        # Read current status
        self._devices = {}
        for device in netdev.bridge_brif(self._TMBR_DEV):
            # Ignore local device that is used pass external traffic into the
            # Treadmill container network.
            if device == self._TM_DEV1:
                continue

            dev_info = _device_info(device)
            self._devices[dev_info['alias']] = dev_info

        # Read the currently assigned vIPs
        for (ip, resource) in self._vips.list():
            self._devices.setdefault(resource, {})['ip'] = ip

        # Mark all the above information as stale
        for device in self._devices:
            self._devices[device]['stale'] = True
示例#5
0
    def _bridge_initialize(self):
        """Reset/initialize the Treadmill node bridge.
        """
        try:
            # FIXME(boysson): This is for migration when TM_DEV0 used to be a
            #                 bridge.
            netdev.link_set_down(self._TM_DEV0)
            netdev.bridge_delete(self._TM_DEV0)
        except subproc.CalledProcessError:
            pass

        try:
            netdev.link_set_down(self._TM_DEV0)
            netdev.link_del_veth(self._TM_DEV0)
        except subproc.CalledProcessError:
            pass

        try:
            netdev.link_set_down(self._TMBR_DEV)
            netdev.bridge_delete(self._TMBR_DEV)
        except subproc.CalledProcessError:
            pass

        netdev.bridge_create(self._TMBR_DEV)
        netdev.bridge_setfd(self._TMBR_DEV, 0)
        netdev.link_add_veth(self._TM_DEV0, self._TM_DEV1)
        netdev.link_set_mtu(self._TM_DEV0, self.ext_mtu)
        netdev.link_set_mtu(self._TM_DEV1, self.ext_mtu)
        netdev.bridge_addif(self._TMBR_DEV, self._TM_DEV1)
        # Force the bridge MAC address to the Treadmill device. This
        # prevents the bridge's MAC from changing when adding/removing
        # container interfaces.
        # (Default Linux bridge behavior is to set the bridge's MAC to be
        # lowest of it's ports).
        tm_mac = netdev.dev_mac(self._TM_DEV1)
        netdev.link_set_addr(self._TMBR_DEV, tm_mac)
        # Bring up the bridge interface
        netdev.link_set_up(self._TMBR_DEV)
        netdev.link_set_up(self._TM_DEV1)
        netdev.addr_add(
            addr='{ip}/16'.format(ip=self._TM_IP),
            devname=self._TM_DEV0
        )
        # Enable route_localnet so that we can redirect traffic from the
        # container to the node's loopback address.
        netdev.dev_conf_route_localnet_set(self._TM_DEV0, True)
        # Bring up the TM interface
        netdev.link_set_up(self._TM_DEV0)
示例#6
0
    def _process_request(self, client_principal, client_addr, policy_name):
        """Process a single request.
        """
        # XXX: Add error handling?
        _LOGGER.info('Request %r:%r (from %r)',
                     client_principal, policy_name, client_addr)

        # See if we have a policy. We use the client_principal as namespace for
        # the policy lookup.
        namespace = urlparse.quote(client_principal.lower(), safe='@')
        # Create a session
        session = _get_policy(
            repository=self._policies_dir,
            namespace=namespace,
            name=policy_name
        )
        if not session:
            _LOGGER.warning('Nonexistent policy %r', policy_name)
            return {
                '_denied': 'no such policy'
            }
        # XXX: Find a better scheme to select session id
        session['id'] = random.randint(0, (2**32) - 1)

        session_name = _session_fname(session)

        # Assign an IP from the network
        gateway_ip = None
        network_idx = None
        for cidr, network in self._networks.items():
            try:
                client_ip = network['pool'].alloc(session_name)
            except Exception:  # pylint: disable=broad-except
                # FIXME: add proper exception handling
                continue
            gateway_ip = network['gateway_ip']
            network_cidr = cidr
            break
        else:
            _LOGGER.critical('Could not assign an IP for %r', session_name)
            return {
                '_error': 'no capacity'
            }

        # Setup the interface
        tun_devname = _utils.wg_dev_create(
            unique_id=session['id'],
            tun_localaddr=gateway_ip,
            tun_remoteaddr=client_ip,
            ll_devname=self._endpoint_dev,
            ll_localaddr=self._endpoint_ip,
            ll_remoteaddr=client_addr
        )
        session['interface'] = tun_devname
        session['client_ip'] = client_ip
        session['gateway_ip'] = gateway_ip
        session['network'] = network_cidr

        # Setup the firewall XXX
        # Enable forwarding
        netdev.dev_conf_forwarding_set(tun_devname, True)

        self._session = session
        with open(os.path.join(self._sessions_dir, session_name), 'w') as f:
            json.dump(session, fp=f, indent=4)

        # Bring up the interface
        netdev.link_set_up(tun_devname)

        # The reply contains the reverse tunnel settings for the client
        return {
            'local_ip': client_ip,
            'remote_ip': gateway_ip,
            'endpoint_ip': self._endpoint_ip,
            'routes': session['routes'],
            'endpoints': session['endpoints'],
            'session_id': session['id'],
        }