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))
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))
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)
def data_received(self, data): # logger.debug('{}: {}'.format(self.user, data)) if self.state == self.INIT: client_greeting = socks.ClientGreeting.from_stream( io.BytesIO(data)) server_greeting = socks.ServerGreeting() self.transport.write(server_greeting.to_bytes()) self.state = self.CMD elif self.state == self.CMD: msg = socks.Message.from_stream(io.BytesIO(data)) global concurrent logger.info('connecting {}:{} ({})'.format(msg.addr[0], msg.addr[1], concurrent)) bind_addr = ('127.0.0.1', 9999) if msg.code is not socks.CMD.CONNECT: rep = socks.Message(socks.VER.SOCKS5, socks.REP.COMMAND_NOT_SUPPORTED, socks.ATYPE.IPV4, bind_addr) self.transport.write(rep.to_bytes()) return # connect asyncio.ensure_future(self.connect(msg.addr[0], msg.addr[1])) elif self.state == self.DATA: self.client_transport.write(data) else: logger.warn('receiving data from user in CLOSED state')
def test_basic(self): socks_msg = socks.Message(socks.VER.SOCKS5, socks.REP.ADDRESS_TYPE_NOT_SUPPORTED, socks.ATYPE.IPV4, ('127.0.0.1', 1234)) m = Reply(3, 4, socks_msg) m1 = Reply.from_stream(io.BytesIO(m.to_bytes())) self.assertEqual(m.to_bytes(), m1.to_bytes())
async def connect(self, host, port): loop = asyncio.get_event_loop() bind_addr = ('127.0.0.1', 80) try: transport, client = \ await loop.create_connection(Client, host, port) except asyncio.TimeoutError: rep = socks.Message(socks.VER.SOCKS5, socks.REP.NETWORK_UNREACHABLE, socks.ATYPE.IPV4, bind_addr) self.transport.write(rep.to_bytes()) self.state = self.CMD return client.server_transport = self.transport self.client_transport = transport bind_addr = transport.get_extra_info('sockname') rep = socks.Message(socks.VER.SOCKS5, socks.REP.SUCCEEDED, socks.ATYPE.IPV4, bind_addr) self.transport.write(rep.to_bytes()) self.state = self.DATA
def test_corner(self): socks_msg = socks.Message(socks.VER.SOCKS5, socks.CMD.CONNECT, socks.ATYPE.IPV4, ('127.0.0.1', 1234)) m = Request(3, 4, socks_msg) self.assertRaises(ProtocolError, Reply.from_stream, io.BytesIO(m.to_bytes()))
def test_basic(self): socks_msg = socks.Message(socks.VER.SOCKS5, socks.CMD.CONNECT, socks.ATYPE.IPV4, ('127.0.0.1', 1234)) m = Request(3, 4, socks_msg) m1 = Request.from_stream(io.BytesIO(m.to_bytes())) self.assertEqual(m.to_bytes(), m1.to_bytes())