コード例 #1
0
    def onMessage(self, dat, isBinary):
        if not isBinary:
            logging.error('non binary ws message received')
            return self.sendClose(3000)

        cmd = ord(self.decrypt(dat[:1]))
        if cmd == self.CMD_RST:
            reason, err = self.parseResetMessage(dat)
            if reason:
                err = translate_err_msg(err)
                logging.info('%s: %s' % (reason, err))
                if self.canReturnErrorPage:
                    self._writer.write(gen_error_page(reason, err))
            self.onResetTunnel()
        elif cmd == self.CMD_DAT:
            dat = self.decrypt(dat[1:])
            if self.tunState != self.TUN_STATE_USING:
                if self.tunState == self.TUN_STATE_IDLE:
                    logging.debug('IDLE should not appear here!')
                # Reset command sent, but server will keep sending data before
                # receiving the command.
                # Can't just throw away dat, because decryptor need to be updated
                return
            self.canReturnErrorPage = False
            self._writer.write(dat)
        else:
            logging.error('wrong command')
コード例 #2
0
ファイル: client.py プロジェクト: ksharpdabu/wstan
    def onMessage(self, dat, isBinary):
        if not isBinary:
            logging.error('non binary ws message received')
            return self.sendClose(3000)

        cmd = ord(self.decrypt(dat[:1]))
        if cmd == self.CMD_RST:
            msg = self.parseResetMessage(dat)
            if not msg.startswith('  '):
                logging.info('tunnel abnormal reset: %s' % msg)
                if self.canReturnErrorPage:
                    title, __, reason = msg.partition(':')
                    self._writer.write(gen_error_page(title, translate_err_msg(reason.strip())))
            self.onResetTunnel()
        elif cmd == self.CMD_DAT:
            dat = self.decrypt(dat[1:])
            if self.tunState != self.TUN_STATE_USING:
                if self.tunState == self.TUN_STATE_IDLE:
                    logging.debug('IDLE should not appear here!')
                # Reset command sent, but server will keep sending data before
                # receiving the command.
                # Can't just throw away dat, because decryptor need to be updated
                return
            self.canReturnErrorPage = False
            self._writer.write(dat)
        else:
            logging.error('wrong command')
コード例 #3
0
ファイル: client.py プロジェクト: krrr/wstan
    def onMessage(self, dat, isBinary):
        if not isBinary:
            logging.error('non binary ws message received')
            return self.sendClose(3000)

        cmd = ord(self.decrypt(dat[:1]))
        if cmd == self.CMD_RST:
            msg = self.parseResetMessage(dat)
            if not msg.startswith('  '):
                logging.info('tunnel abnormal reset: %s' % msg)
                if self.canReturnErrorPage:
                    title, __, reason = msg.partition(':')
                    self._writer.write(gen_error_page(title, translate_err_msg(reason.strip())))
            self.onResetTunnel()
        elif cmd == self.CMD_DAT:
            dat = self.decrypt(dat[1:])
            if self.tunState != self.TUN_STATE_USING:
                # Reset command sent, but server will keep sending data before
                # receiving the command.
                # Can't just throw away dat, because decryptor need to be updated
                return
            self.canReturnErrorPage = False
            self._writer.write(dat)
        else:
            logging.error('wrong command')
コード例 #4
0
ファイル: client.py プロジェクト: ksharpdabu/wstan
 def onClose(self, *args):
     if not self.tunOpen.done():
         # sometimes reason can be None in extremely poor network
         msg = self.wasNotCleanReason or ''
         msg = translate_err_msg(msg)
         logging.error("can't connect to server: %s" % msg)
         if self.wasNotCleanReason and self.canReturnErrorPage:  # write before closing writer
             self._writer.write(gen_error_page("can't connect to wstan server", msg))
         RelayMixin.onClose(self, *args, logWarn=False)
         self.tunOpen.cancel()
     else:
         RelayMixin.onClose(self, *args)
     self.tryRemoveFromPool()
コード例 #5
0
    def startProxy(cls, addrHeader, dat, reader, writer):
        canErr = can_return_error_page(dat)

        if cls.pool:
            logging.debug('reuse tunnel from pool (total %s)' % len(cls.pool))
            tun = cls.pool[0]
            tun.checkTimeoutTask.cancel()
            tun.checkTimeoutTask = None
            tun.tryRemoveFromPool()
            tun.setAutoPing(cls.TUN_AUTO_PING_INTERVAL,
                            cls.TUN_AUTO_PING_TIMEOUT)
            tun.sendMessage(tun.makeRelayHeader(addrHeader, dat), True)
        else:
            try:
                sock = None
                if config.proxy:
                    sock = yield from setup_http_tunnel()

                tun = (yield from loop.create_connection(
                    factory,
                    None if sock else config.uri_addr,
                    None if sock else config.uri_port,
                    server_hostname=config.uri_addr
                    if config.tun_ssl else None,
                    sock=sock,
                    ssl=config.tun_ssl))[1]
                # lower latency by sending relay header and data in ws handshake
                tun.customUriPath = '/' + base64.urlsafe_b64encode(
                    tun.makeRelayHeader(addrHeader, dat)).decode()
                async_(tun.restartHandshake())
                yield from wait_for(tun.tunOpen, tun.openHandshakeTimeout)
            except Exception as e:
                if isinstance(e,
                              (asyncio.TimeoutError, asyncio.CancelledError)):
                    # sometimes reason can be None in extremely poor network
                    msg = tun.wasNotCleanReason or ''
                else:
                    msg = str(e)
                msg = translate_err_msg(msg)
                logging.error("can't connect to server: %s" % msg)
                if canErr:
                    writer.write(
                        gen_error_page("can't connect to wstan server", msg))
                return writer.close()
        tun.canReturnErrorPage = canErr
        tun.setProxy(reader, writer)
コード例 #6
0
ファイル: client.py プロジェクト: ksharpdabu/wstan
    def startProxy(cls, addrHeader, dat, reader, writer):
        if not dat:
            logging.debug('startProxy with no data')
        canErr = can_return_error_page(dat)

        if cls.pool:
            logging.debug('reuse tunnel from pool (total %s)' % len(cls.pool))
            tun = cls.pool[0]
            tun.checkTimeoutTask.cancel()
            tun.checkTimeoutTask = None
            tun.tryRemoveFromPool()
            tun.setAutoPing(cls.TUN_AUTO_PING_INTERVAL, cls.TUN_AUTO_PING_TIMEOUT)
            tun.canReturnErrorPage = canErr
            tun.setProxy(reader, writer)
            tun.sendMessage(tun.makeRelayHeader(addrHeader, dat), True)
        else:
            try:
                sock = None
                if config.proxy:
                    sock = yield from setup_http_tunnel()

                tun = (yield from loop.create_connection(
                    factory, None if sock else config.uri_addr, None if sock else config.uri_port,
                    server_hostname=config.uri_addr if config.tun_ssl else None,
                    sock=sock, ssl=config.tun_ssl))[1]
                # Lower latency by sending relay header and data in ws handshake
                tun.customUriPath = factory.path + base64.urlsafe_b64encode(
                        tun.makeRelayHeader(addrHeader, dat)).decode()
                tun.canReturnErrorPage = canErr
                tun.setProxy(reader, writer, startPushLoop=False)
                async_(tun.restartHandshake())
                # Data may arrive before setProxy if wait for onOpen here
                # and then set proxy.
            except Exception as e:
                msg = translate_err_msg(str(e))
                logging.error("can't connect to server: %s" % msg)
                if canErr:
                    writer.write(gen_error_page("can't connect to wstan server", msg))
                return writer.close()
コード例 #7
0
ファイル: client.py プロジェクト: gvsurenderreddy/wstan
    def startProxy(cls, addrHeader, dat, reader, writer):
        canErr = can_return_error_page(dat)

        if cls.pool:
            logging.debug('reuse tunnel from pool (total %s)' % len(cls.pool))
            tun = cls.pool.popleft()
            tun.checkTimeoutTask.cancel()
            tun.checkTimeoutTask = None
            tun.inPool = False
            tun.disableAutoPing()
            tun.sendMessage(tun.makeRelayHeader(addrHeader, dat), True)
        else:
            try:
                sock = None
                if config.proxy:
                    sock = yield from setup_http_tunnel()

                tun = (yield from loop.create_connection(
                    factory, None if sock else config.uri_addr, None if sock else config.uri_port,
                    server_hostname=config.uri_addr if config.tun_ssl else None,
                    sock=sock, ssl=config.tun_ssl))[1]
                # lower latency by sending relay header and data in ws handshake
                tun.customUriPath = '/' + base64.urlsafe_b64encode(tun.makeRelayHeader(addrHeader, dat)).decode()
                asyncio.async(tun.restartHandshake())
                yield from asyncio.wait_for(tun.tunOpen, tun.openHandshakeTimeout)
            except Exception as e:
                if isinstance(e, (asyncio.TimeoutError, asyncio.CancelledError)):
                    # sometimes reason can be None in extremely poor network
                    msg = tun.wasNotCleanReason or ''
                else:
                    msg = str(e)
                msg = translate_err_msg(msg)
                logging.error("can't connect to server: %s" % msg)
                if canErr:
                    writer.write(gen_error_page("can't connect to wstan server", msg))
                return writer.close()
        tun.canReturnErrorPage = canErr
        tun.setProxy(reader, writer)
コード例 #8
0
ファイル: client.py プロジェクト: gvsurenderreddy/wstan
    def onMessage(self, dat, isBinary):
        if not isBinary:
            logging.error('non binary ws message received')
            return self.sendClose(3000)

        cmd = ord(self.decrypt(dat[:1]))
        if cmd == self.CMD_RST:
            msg = self.parseResetMessage(dat)
            if not msg.startswith('  '):
                logging.info('tunnel abnormal reset: %s' % msg)
                if self.canReturnErrorPage:
                    title, __, reason = msg.partition(':')
                    self._writer.write(gen_error_page(title, translate_err_msg(reason.strip())))
            self.onResetTunnel()
        elif cmd == self.CMD_DAT:
            dat = self.decrypt(dat[1:])
            if self.tunState != self.TUN_STATE_USING:
                # why this happens?
                return
            self.canReturnErrorPage = False
            self._writer.write(dat)
        else:
            logging.error('wrong command')
コード例 #9
0
    def openTunnel(cls, target, dat, reader, writer, retryCount=0):
        logging.info('requesting %s:%d' % target)

        if not dat:
            logging.debug('openTunnel with no data')
        canErr = can_return_error_page(dat)

        if cls.pool:  # reuse from pool
            logging.debug('reuse tunnel from pool (total %s)' % len(cls.pool))
            tun = cls.pool[0]
            tun.checkTimeoutTask.cancel()
            tun.checkTimeoutTask = None
            tun.tryRemoveFromPool()
            tun.setAutoPing(cls.TUN_AUTO_PING_INTERVAL,
                            cls.TUN_AUTO_PING_TIMEOUT)
            tun.canReturnErrorPage = canErr
            tun.setProxy(reader, writer)
            tun.sendMessage(tun.makeRelayHeader(target, dat), True)
            return

        # new tunnel
        try:
            if retryCount >= cls.MAX_RETRY_COUNT:
                raise ConnectionResetError(
                    'run into tcp reset, all retries failed')

            sock = None
            if config.proxy:
                sock = yield from setup_http_tunnel()

            tun = factory()
            # Lower latency by sending relay header and data in ws handshake
            tun.customUriPath = factory.path + base64.urlsafe_b64encode(
                tun.makeRelayHeader(target, dat)).decode()
            tun.canReturnErrorPage = canErr
            # Data may arrive before setProxy if wait for tunOpen here and then set proxy.
            tun.setProxy(reader, writer,
                         startPushLoop=False)  # push loop will start in onOpen

            if config.tfo:
                assert not config.proxy and not config.tun_ssl
                tun.noSendHandshake = True
                tun.startHandshake()
                # tfo is meaningless if handshake data can't fit into TCP SYN packet
                # switch back to normal sock_connect just in case my Windows tfo extension has bug
                tfoDat = tun.http_request_data if len(
                    tun.http_request_data) <= 1400 else None
                sock = yield from my_sock_connect(config.uri_addr,
                                                  config.uri_port,
                                                  tfo_dat=tfoDat)
                # it will return after SYN,ACK received regardless of TFO
                if not tfoDat:
                    loop.sock_sendall(sock, tun.http_request_data)

            yield from loop.create_connection(
                lambda: tun,
                None if sock else config.uri_addr,
                None if sock else config.uri_port,
                server_hostname=config.uri_addr if config.tun_ssl else None,
                sock=sock,
                ssl=config.tun_ssl)
        except Exception as e:
            msg = translate_err_msg(str(e))
            dest = 'proxy' if config.proxy and not sock else 'wstan server'
            logging.error("can't connect to %s: %s" % (dest, msg))
            if canErr:
                writer.write(gen_error_page("can't connect to " + dest, msg))
            return writer.close()

        try:
            yield from wait_for(tun.tunOpen, None)
        except CancelledError:
            # sometimes reason can be None in extremely poor network
            msg = tun.wasNotCleanReason or ''

            if isinstance(tun.connLostReason, ConnectionResetError):
                # GFW random reset HTTP stream it can't recognize, just retry
                return async_(
                    cls.openTunnel(target, dat, reader, writer,
                                   retryCount + 1))

            msg = translate_err_msg(msg)
            logging.error("can't connect to server: %s" % msg)
            if tun.wasNotCleanReason and tun.canReturnErrorPage:  # write before closing writer
                writer.write(
                    gen_error_page("can't connect to wstan server", msg))
            return writer.close()

        if retryCount > 0:
            logging.debug('tcp reset happen, retried %d times' % retryCount)