def _new_websocket_client(self, container, token, uuid): if token != container.websocket_token: raise exception.InvalidWebsocketToken(token) access_url = '%s?token=%s&uuid=%s' % (CONF.websocket_proxy.base_url, token, uuid) self._verify_origin(access_url) if container.websocket_url: target_url = container.websocket_url escape = "~" close_wait = 0.5 wscls = WebSocketClient(host_url=target_url, escape=escape, close_wait=close_wait) wscls.connect() self.target = wscls else: raise exception.InvalidWebsocketUrl() # Start proxying try: self.do_websocket_proxy(self.target.ws) except Exception: if self.target.ws: self.target.ws.close() self.vmsg(_("Websocket client or target closed")) raise
def _new_exec_client(self, container, token, uuid, exec_id): exec_instance = None for e in container.exec_instances: if token == e.token and exec_id == e.exec_id: exec_instance = e if not exec_instance: raise exception.InvalidWebsocketToken(token) access_url = '%s?token=%s&uuid=%s' % (CONF.websocket_proxy.base_url, token, uuid) self._verify_origin(access_url) client = docker.APIClient(base_url=exec_instance.url) tsock = client.exec_start(exec_id, socket=True, tty=True) if hasattr(tsock, "_sock"): # NOTE(hongbin): dockerpy returns different socket class depending # on python version and base_url (see _get_raw_response_socket) so # we need to handle it in here. tsock = tsock._sock try: self.do_proxy(tsock) finally: if tsock: tsock.shutdown(socket.SHUT_RDWR) tsock.close() self.vmsg(_("%s: Closed target") % exec_instance.url)
def new_websocket_client(self): """Called after a new WebSocket connection has been established.""" # Reopen the eventlet hub to make sure we don't share an epoll # fd with parent and/or siblings, which would be bad from eventlet import hubs hubs.use_hub() # The zun expected behavior is to have token # passed to the method GET of the request parse = urlparse.urlparse(self.path) if parse.scheme not in ('http', 'https'): # From a bug in urlparse in Python < 2.7.4 we cannot support # special schemes (cf: https://bugs.python.org/issue9374) if sys.version_info < (2, 7, 4): raise exception.ZunException( _("We do not support scheme '%s' under Python < 2.7.4, " "please use http or https") % parse.scheme) query = parse.query token = urlparse.parse_qs(query).get("token", [""]).pop() uuid = urlparse.parse_qs(query).get("uuid", [""]).pop() dbapi = db_api._get_dbdriver_instance() ctx = context.get_admin_context(all_tenants=True) if uuidutils.is_uuid_like(uuid): container = dbapi.get_container_by_uuid(ctx, uuid) else: container = dbapi.get_container_by_name(ctx, uuid) if token != container.websocket_token: raise exception.InvalidWebsocketToken(token) access_url = '%s?token=%s&uuid=%s' % (CONF.websocket_proxy.base_url, token, uuid) # Verify Origin expected_origin_hostname = self.headers.get('Host') if ':' in expected_origin_hostname: e = expected_origin_hostname if '[' in e and ']' in e: expected_origin_hostname = e.split(']')[0][1:] else: expected_origin_hostname = e.split(':')[0] expected_origin_hostnames = CONF.websocket_proxy.allowed_origins expected_origin_hostnames.append(expected_origin_hostname) origin_url = self.headers.get('Origin') # missing origin header indicates non-browser client which is OK if origin_url is not None: origin = urlparse.urlparse(origin_url) origin_hostname = origin.hostname origin_scheme = origin.scheme if origin_hostname == '' or origin_scheme == '': detail = _("Origin header not valid.") raise exception.ValidationError(detail) if origin_hostname not in expected_origin_hostnames: detail = _("Origin header does not match this host.") raise exception.ValidationError(detail) if not self.verify_origin_proto(access_url, origin_scheme): detail = _("Origin header protocol does not match this host.") raise exception.ValidationError(detail) if container.websocket_url: target_url = container.websocket_url escape = "~" close_wait = 0.5 wscls = WebSocketClient(host_url=target_url, escape=escape, close_wait=close_wait) wscls.connect() self.target = wscls else: raise exception.InvalidWebsocketUrl() # Start proxying try: self.do_proxy(self.target.ws) except Exception as e: if self.target.ws: self.target.ws.close() self.vmsg(_("%Websocket client or target closed")) raise