Example #1
0
 async def connect(self, host, port):
     self.state = self.CMD
     loop = asyncio.get_event_loop()
     bind_addr = ('255.255.255.255', 0)
     try:
         logger.info('connecting {}:{}'.format(host, port))
         fut = loop.create_connection(Client, host, port)
         transport, client = await \
             asyncio.wait_for(fut, timeout=config.timeout)
     except (asyncio.TimeoutError, ConnectionRefusedError,
             socket.gaierror) as e:
         logger.warn('connect {}'.format(e))
         socks_err = socks.Message(socks.VER.SOCKS5,
                                   socks.REP.NETWORK_UNREACHABLE,
                                   socks.ATYPE.IPV4, bind_addr)
         rep = protocol.Reply(self.remote, self.user, socks_err)
         self.tunnel_transport.write(rep.to_packet(self.fuzz))
         self.state = self.IDLE
         return
     client.channel = self
     self.remote_transport = transport
     self.remote = transport._sock_fd
     bind_addr = transport.get_extra_info('sockname')
     socks_ok = socks.Message(socks.VER.SOCKS5, socks.REP.SUCCEEDED,
                              socks.ATYPE.IPV4, bind_addr)
     rep = protocol.Reply(self.remote, self.user, socks_ok)
     self.tunnel_transport.write(rep.to_packet(self.fuzz))
     self.state = self.DATA
     logger.debug('channel {} opened'.format(self))
Example #2
0
    async def _handle_client(self, client_reader, client_writer):
        # ignore client greeting
        data = await client_reader.read(32)
        logger.debug('Ignore client greeting ({} bytes)'.format(len(data)))
        server_greeting = socks.ServerGreeting()
        client_writer.write(server_greeting.to_bytes())
        # recv CMD
        msg = await socks.Message.from_reader(client_reader)
        if msg.code is not socks.CMD.CONNECT:
            logger.warn('unhandle msg {}'.format(msg))
            return
        fut = asyncio.open_connection(msg.addr[0], msg.addr[1])
        try:
            remote_reader, remote_writer = await asyncio.wait_for(fut, 3)
        except (asyncio.TimeoutError, ConnectionRefusedError):
            logger.warn('connet {}:{} failed'.format(msg.addr[0], msg.addr[1]))
            err_reply = socks.Message(ver=socks.VER.SOCKS5,
                                      code=socks.REP.CONNECTION_REFUSED,
                                      atype=socks.ATYPE.IPV4,
                                      addr=('127.0.0.1', 9999))
            client_writer.write(err_reply.to_bytes())
            return

        logger.info('connected to {}:{}'.format(msg.addr[0], msg.addr[1]))
        # send REP
        bind_address = remote_writer.transport._extra['sockname']
        reply = socks.Message(ver=socks.VER.SOCKS5,
                              code=socks.REP.SUCCEEDED,
                              atype=socks.ATYPE.IPV4,
                              addr=bind_address)
        client_writer.write(reply.to_bytes())
        # piping
        await asyncio.gather(pipe('remote', remote_reader, client_writer),
                             pipe('user', client_reader, remote_writer))
Example #3
0
    async def start_tunnel(self, loop, host, port):
        logger.info('negotiate with server {}:{}'.format(
            config.server_host, config.server_port))
        reader, writer = await asyncio.open_connection(host, port)
        # > Hello
        hello_request = protocol.Hello()
        await self.safe_write(writer, hello_request.to_packet(self.cipher))
        # < Hello
        hello_response = await protocol.async_read_packet(reader, self.cipher)
        logger.debug(hello_response)
        # > HandShake
        shake_request = protocol.HandShake(timestamp=hello_response.timestamp)
        await self.safe_write(writer, shake_request.to_packet(self.cipher))
        # < HandShake
        shake_response = await protocol.async_read_packet(reader, self.cipher)
        logger.debug(shake_response)
        logger.info('negotiate done, using fuzz: {}'.format(
            shake_response.fuzz))
        self.fuzz = shake_response.fuzz
        self.tunnel_reader = reader
        self.tunnel_writer = writer
        self.tunnel_task = asyncio.Task(self._handle_tunnel(reader, writer))

        def tunnel_done(task):
            logger.warn('tunnel is closed')
            sys.exit(2)

        self.tunnel_task.add_done_callback(tunnel_done)
        return True
Example #4
0
 def data_received(self, data):
     length = len(data)
     if self.remains > 0:
         # remaining part of previous packet
         if length == self.remains:
             self.buf.extend(data)
             self.packet_received(self.buf)
             self.remains = 0
             self.buf.clear()
         elif length < self.remains:
             self.buf.extend(data)
             self.remains -= length
         elif length > self.remains:
             self.buf.extend(data[:self.remains])
             self.packet_received(self.buf)
             self.remains = 0
             self.buf.clear()
             self.data_received(data[self.remains:])
         return
     # start of packet
     assert length >= 6, 'packet length too small'
     need_len, = struct.unpack('!I', data[2:6])
     real_len = length - 6
     self.remains = need_len - real_len
     if self.remains == 0:
         self.packet_received(data)
     elif self.remains > 0:
         self.buf.extend(data)
     elif self.remains < 0:
         logger.debug('more than one packet recevied at once')
         self.packet_received(data[:6 + need_len])
         remaining = data[6 + need_len:]
         self.remains = 0
         self.data_received(remaining)
Example #5
0
 async def _handle_user(self, user):
     # ignore client SOCKS5 greeting
     data = await user.reader.read(256)
     logger.debug('ignore SOCK5 greeting ({} bytes)'.format(len(data)))
     # response greeting without auth
     server_greeting = socks.ServerGreeting()
     await self.safe_write(user.writer, server_greeting.to_bytes())
     # recv CMD
     try:
         msg = await socks.Message.from_reader(user.reader)
     except asyncio.streams.IncompleteReadError:
         self._delete_user(user)
         return
     if msg.code is not socks.CMD.CONNECT:
         logger.warn('unhandle msg {}'.format(msg))
         rep = socks.Message(socks.VER.SOCKS5,
                             socks.REP.COMMAND_NOT_SUPPORTED,
                             socks.ATYPE.IPV4, ('0', 0))
         await self.safe_write(user.writer, rep.to_bytes())
         return
     logger.info('connecting {}:{}'.format(msg.addr[0], msg.addr[1]))
     # send to tunnel
     connect_reqeust = protocol.Request(user.user_id, 0, msg)
     await self.safe_write(self.tunnel_writer,
                           connect_reqeust.to_packet(self.fuzz))
     await self._pipe_user(user)
Example #6
0
 def connection_lost(self, exc):
     global concurrent
     concurrent -= 1
     logger.debug('connection to user lost')
     self.state = self.CLOSED
     if self.client_transport is not None:
         logger.debug('abort client')
         self.client_transport.abort()
Example #7
0
 def close(self):
     if self.state == self.IDLE:
         return
     self.state = self.IDLE
     if self.remote_transport is not None:
         self.remote_transport.abort()
     packet = protocol.Close(self.user)
     self.tunnel_transport.write(packet.to_packet(self.fuzz))
     logger.debug('channel {} closed'.format(self))
Example #8
0
 def connection_made(self, transport):
     global concurrent
     concurrent += 1
     logger.debug('{} connected'.format(
         transport.get_extra_info('peername')))
     self.transport = transport
     self.client_transport = None
     self.user = transport.get_extra_info('peername')
     self.state = self.INIT
Example #9
0
 def connection_made(self, transport):
     logger.debug('client {}:{} connected'.format(
         *transport.get_extra_info('peername')))
     self.transport = transport
     self.tunnel = None
     self.state = self.GREETING
     self.buf = bytearray()
     self.remains = 0
     self.cipher = cryption.AES256CBC(config.password)
     self.fuzz = None
Example #10
0
    def _accept_user(self, user_reader, user_writer):
        logger.debug('user accepted')
        user = User(user_reader, user_writer)
        task = asyncio.Task(self._handle_user(user))
        user.task = task
        self.users[user.user_id] = user

        def user_done(task):
            logger.debug('user task done')

        task.add_done_callback(user_done)
Example #11
0
    def stop(self, loop):
        """
        Stops the TCP server, i.e. closes the listening socket(s).

        This method runs the loop until the server sockets are closed.
        """
        if self.server is not None:
            logger.debug('canceling tasks')
            for task in self.clients:
                task.cancel()
            loop.run_until_complete(asyncio.wait([t for t in self.clients]))
            self.server.close()
            loop.run_until_complete(self.server.wait_closed())
            self.server = None
Example #12
0
async def pipe(name, reader, writer):
    while True:
        try:
            data = await reader.read(2048)
        except ConnectionResetError as e:
            logger.warn('connection reset by ' + name)
            break
        except asyncio.CancelledError as e:
            logger.debug('pipe canceled.')
            break
        if len(data) == 0:
            logger.debug('{} connection closed'.format(name))
            break
        writer.write(data)
    return None
Example #13
0
    def _accept_client(self, client_reader, client_writer):
        """
        This method accepts a new client connection and creates a Task
        to handle this client.  self.clients is updated to keep track
        of the new client.
        """

        logger.debug('=== begin ===')
        # start a new Task to handle this specific client connection
        task = asyncio.Task(self._handle_client(client_reader, client_writer))
        self.clients[task] = (client_reader, client_writer)

        def client_done(task):
            logger.debug('=== end ===')
            del self.clients[task]

        task.add_done_callback(client_done)
Example #14
0
 async def _handle_tunnel(self, reader, writer):
     logger.debug('_handle_tunnel started')
     while True:
         packet = await protocol.async_read_packet(reader, self.fuzz)
         if packet.mtype is protocol.MTYPE.REPLY:
             # received a SOCKS reply, update mapping
             # and forward to corresponding user
             remote_id = packet.src
             user_id = packet.dst
             user = self._get_user(user_id)
             if user is None:
                 # Tell server to close
                 continue
             await self.safe_write(user.writer, packet.msg.to_bytes())
             user.remote_id = remote_id
         elif packet.mtype is protocol.MTYPE.RELAYING:
             # received raw data, forwarding
             remote_id = packet.src
             user_id = packet.dst
             user = self._get_user(user_id)
             if user is None:
                 # Tell server to close
                 continue
             await self.safe_write(user.writer, packet.payload)
         elif packet.mtype is protocol.MTYPE.CLOSE:
             # close user tansport
             user_id = packet.src
             logger.debug(
                 'remote disconnected, close user {}'.format(user_id))
             user = self._get_user(user_id)
             if user is None:
                 # ignore
                 continue
             self._delete_user(user)
         else:
             logger.warn('unknown packet {}'.format(packet))
     logger.debug('_handle_tunnel exited')
Example #15
0
 def connection_lost(self, exc):
     self.state = self.CLOSING
     logger.debug('client {}:{} disconnected'.format(
         *self.transport.get_extra_info('peername')))
     if self.tunnel is not None:
         self.tunnel.close()
Example #16
0
 def _user_closed(self, user):
     logger.debug('{} closed'.format(user))
     if user.established:
         self.tunnel_writer.write(
             protocol.Close(user.user_id).to_packet(self.fuzz))
     user.writer.transport.abort()
Example #17
0
 def user_done(task):
     logger.debug('user task done')
Example #18
0
 def client_done(task):
     logger.debug('=== end ===')
     del self.clients[task]
Example #19
0
 def connection_lost(self, exc):
     logger.debug('connection to server lost')
     self.state = self.CLOSED
     if self.server_transport is not None:
         logger.debug('abort server')
         self.server_transport.abort()