def _attempt_finish_socks_handshake(self): # Receive the first byte of the server reply using the # underlying recv() primitive, and suspend this operation if # it comes back with EAGAIN, or fail it if it gives an error. # Callers of connect_ex expect to get EINPROGRESS, not EAGAIN. logger.debug("Attempting to read SOCKS reply.") try: resp0 = self._sock.recv(1) except socket.error as e: if e.errno in _ERRNO_RETRY: logger.debug("SOCKS reply not yet available.") return errno.EINPROGRESS logger.debug("Connection failure: %s", e) self._connecting = False self._conn_err = e.errno return e.errno if resp0 != "\x05": self._connecting = False raise error.SOCKSv5Error( "Protocol error: server reply begins with 0x%02x, not 0x05" % ord(resp0)) # We are now committed to receiving and processing the server # response. resp = self._recv_all(3) if resp[0] != "\x00": self._connecting = False val = ord(resp[0]) if val in socks5_errors: self._conn_err = socks5_errors[val] logger.debug("Connection failure at protocol level: %s", os.strerror(self._conn_err)) return self._conn_err else: raise error.SOCKSv5Error("Unrecognized SOCKSv5 error: %d" % val) # Read and discard the rest of the reply, which consists of an # address type (1 byte), variable-length address (depending on the # address type), and port number (2 bytes). if resp[2] == "\x01": self._recv_all(4) elif resp[2] == "\x03": length = self._recv_all(1) self._recv_all(ord(length)) else: self._recv_all(16) self._recv_all(2) # We are now officially connected. logger.debug("Now connected to %s:%d.", *self._peer_addr) self._connected = True return 0
def connect(self, addr_tuple): """ Tell SOCKS server to connect to our destination. """ dst_addr, dst_port = addr_tuple[0], int(addr_tuple[1]) self._authenticate() # Tell SOCKS server to connect to destination. self.sendall("\x05\x01\x00\x01%s%s" % (socket.inet_aton(dst_addr), struct.pack(">H", dst_port))) resp = self.recv(4) if resp[1] != "\x00": raise error.SOCKSv5Error("Connection failed. Server responded " "with 0x%s." % resp[0].encode("hex")) # Depending on address type, get address. if resp[3] == "\x01": self.recv(4) elif resp[3] == "\x03": length = self.recv(1) self.recv(length) else: self.recv(16) # Get port. self.recv(2)
def resolve(self, domain): """ Resolve the given domain using Tor's SOCKS resolution extension. """ domain_len = len(domain) if domain_len > 255: raise error.SOCKSv5Error("Domain must not be longer than 255 " "characters, but %d given." % domain_len) # Tor defines a new command value, \x0f, that is used for domain # resolution. self._send_all("\x05\xf0\x00\x03%s%s%s" % (chr(domain_len), domain, "\x00\x00")) resp = self._recv_all(10) if resp[:2] != "\x05\x00": raise error.SOCKSv5Error("Invalid server response: 0x%s" % resp[1].encode("hex")) return socket.inet_ntoa(resp[4:8])
def resolve(self, hostname): "Resolves the given domain name over the proxy" host = hostname.encode("utf-8") # First connect to the local proxy self.negotiate() send_queue(socks._BaseSocket.getsockname(self)) req = struct.pack('BBB', 0x05, 0xF0, 0x00) req += chr(0x03).encode() + chr(len(host)).encode() + host req = req + struct.pack(">H", 8444) socks._BaseSocket.sendall(self, req) # Get the response ip = "" resp = socks._BaseSocket.recv(self, 4) if resp[0:1] != chr(0x05).encode(): socks._BaseSocket.close(self) raise error.SOCKSv5Error("SOCKS Server error") elif resp[1:2] != chr(0x00).encode(): # Connection failed socks._BaseSocket.close(self) if ord(resp[1:2]) <= 8: raise error.SOCKSv5Error("SOCKS Server error {}".format( ord(resp[1:2]))) else: raise error.SOCKSv5Error("SOCKS Server error 9") # Get the bound address/port elif resp[3:4] == chr(0x01).encode(): ip = socket.inet_ntoa(socks._BaseSocket.recv(self, 4)) elif resp[3:4] == chr(0x03).encode(): resp = resp + socks._BaseSocket.recv(self, 1) ip = socks._BaseSocket.recv(self, ord(resp[4:5])) else: socks._BaseSocket.close(self) raise error.SOCKSv5Error("SOCKS Server error.") boundport = struct.unpack(">H", socks._BaseSocket.recv(self, 2))[0] socks._BaseSocket.close(self) return ip
def connect(self, addr_tuple): """ Tell SOCKS server to connect to our destination. """ dst_addr, dst_port = addr_tuple[0], int(addr_tuple[1]) self._authenticate() # Tell SOCKS server to connect to destination. self.sendall("\x05\x01\x00\x01%s%s" % (socket.inet_aton(dst_addr), struct.pack(">H", dst_port))) resp = self._recv_all(4) if resp[1] != "\x00": val = int(resp[1].encode("hex"), 16) if 0 <= val < len(socks5_errors): raise error.SOCKSv5Error("SOCKSv5 connection failed because: " "%s" % socks5_errors[val]) else: raise error.SOCKSv5Error("Unexpected SOCKSv5 error: %d" % val) # Depending on address type, get address. if resp[3] == "\x01": self._recv_all(4) elif resp[3] == "\x03": length = self._recv_all(1) self._recv_all(length) else: self._recv_all(16) # Get port. self._recv_all(2)
def _authenticate(self): """ Authenticate to our SOCKSv5 server. """ assert (proxy_addr is not None) and (proxy_port is not None) # Connect to SOCKSv5 server. We use version 5 and one authentication # method, which is "no authentication". self._sock.connect((proxy_addr, proxy_port)) self._send_all("\x05\x01\x00") resp = self._recv_all(2) if resp != "\x05\x00": raise error.SOCKSv5Error("Invalid server response: 0x%s" % resp.encode("hex")) send_queue(self.getsockname())
def _authenticate(self): """ Authenticate to our SOCKSv5 server. """ assert (proxy_addr is not None) and (proxy_port is not None) # Connect to SOCKSv5 server. We use version 5 and one authentication # method, which is "no authentication". try: orig_socket.connect(self, (proxy_addr, proxy_port)) except Exception as err: logger.warning("connect() failed: %s" % err) sys.exit(1) self.sendall("\x05\x01\x00") resp = self._recv_all(2) if resp != "\x05\x00": raise error.SOCKSv5Error("Invalid server response: 0x%s" % resp.encode("hex")) send_queue(self.getsockname())