async def resolve(config, request, use_proxy=True): config.logger.debug(str(parse_message(request))) remote = ExtendedSocket() if use_proxy: await remote.connect(config.proxy_addr) await remote.sendall(b'\x05\x01\x00') assert (await remote.ensure_recv(2)) == b'\x05\x00' await remote.sendall(b'\x05\x01\x00\x01' + socket.inet_aton(config.remote_addr[0]) + struct.pack("!H", config["remote_addr"][1])) kind = (await remote.ensure_recv(4))[3] if kind == 1: await remote.ensure_recv(4) elif kind == 3: length = (await remote.ensure_recv(1))[0] await remote.ensure_recv(length) elif kind == 4: await remote.ensure_recv(16) else: raise ValueError(f'Invalid ADDR type {kind}') await remote.ensure_recv(2) else: await remote.connect(config.direct_addr) await remote.sendall(struct.pack(">H", len(request))) await remote.sendall(request) length = await remote.recv_uint16be() resp = await remote.ensure_recv(length) config.logger.debug(str(parse_message(resp))) return resp
def pack_ipv4(addr, userid: bytes = b"\x01\x01") -> bytes: host, port = addr tail = b"" try: packed = socket.inet_aton(host) except OSError: packed = b"\x00\x00\x00\x01" tail = host.encode() + b"\x00" return port.to_bytes(2, "big") + packed + userid + b"\x00" + tail
def pack_addr(addr): host, port = addr try: # IPV4 packed = b'\x01' + socket.inet_aton(host) except OSError: try: # IPV6 packed = b'\x04' + socket.inet_pton(socket.AF_INET6, host) except OSError: # hostname packed = host.encode('ascii') packed = b'\x03' + len(packed).to_bytes(1, 'big') + packed return packed + port.to_bytes(2, 'big')
def pack_addr(addr): host, port = addr try: # IPV4 packed = b"\x01" + socket.inet_aton(host) except OSError: try: # IPV6 packed = b"\x04" + socket.inet_pton(socket.AF_INET6, host) except OSError: # hostname packed = host.encode("ascii") packed = b"\x03" + len(packed).to_bytes(1, "big") + packed return packed + port.to_bytes(2, "big")
async def handle(self, conn, addr): logging.info(f'Accepting connection from {addr}') # greeting header # read and unpack 2 bytes from a client header = await conn.recv(2) version, nmethods = struct.unpack("!BB", header) # socks 5 assert version == SOCKS_VERSION assert nmethods > 0 # get available methods methods = await self.get_available_methods(conn, nmethods) # accept only USERNAME/PASSWORD auth if 2 not in set(methods): # close connection conn.close() return # send welcome message await conn.sendall(struct.pack("!BB", SOCKS_VERSION, 2)) if not await self.verify_credentials(conn): return # request version, cmd, _, address_type = struct.unpack("!BBBB", await conn.recv(4)) assert version == SOCKS_VERSION if address_type == 1: # IPv4 address = socket.inet_ntoa(await conn.recv(4)) elif address_type == 3: # Domain name domain_length = ord(await conn.recv(1)) address = await conn.recv(domain_length) port = struct.unpack('!H', await conn.recv(2))[0] # reply try: if cmd == 1: # CONNECT remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if self.eip != '0.0.0.0': remote.bind((self.eip, 0)) await remote.connect((address, port)) bind_address = remote.getsockname() logging.info(f'Connected to {(address, port)}') else: conn.close() return addr = struct.unpack("!I", socket.inet_aton(bind_address[0]))[0] port = bind_address[1] reply = struct.pack("!BBBBIH", SOCKS_VERSION, 0, 0, 1, addr, port) except Exception as err: logging.error(err) # return connection refused error reply = self.generate_failed_reply(address_type, 5) await conn.sendall(reply) # establish data exchange if reply[1] == 0 and cmd == 1: job1 = await spawn(self.forward_tcp, conn, remote) job2 = await spawn(self.forward_tcp, remote, conn) await job1.join() await job2.join() await conn.close()