| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  | # Public Domain SOCKS proxy protocol implementation | 
					
						
							|  |  |  | # Adapted from https://gist.github.com/bluec0re/cafd3764412967417fd3 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | from __future__ import unicode_literals | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  | # References: | 
					
						
							|  |  |  | # SOCKS4 protocol http://www.openssh.com/txt/socks4.protocol | 
					
						
							|  |  |  | # SOCKS4A protocol http://www.openssh.com/txt/socks4a.protocol | 
					
						
							|  |  |  | # SOCKS5 protocol https://tools.ietf.org/html/rfc1928 | 
					
						
							|  |  |  | # SOCKS5 username/password authentication https://tools.ietf.org/html/rfc1929 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  | import collections | 
					
						
							|  |  |  | import socket | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  | from .compat import ( | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |     compat_ord, | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |     compat_struct_pack, | 
					
						
							|  |  |  |     compat_struct_unpack, | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  | __author__ = 'Timo Schmid <coding@timoschmid.de>' | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  | SOCKS4_VERSION = 4 | 
					
						
							|  |  |  | SOCKS4_REPLY_VERSION = 0x00 | 
					
						
							|  |  |  | # Excerpt from SOCKS4A protocol: | 
					
						
							|  |  |  | # if the client cannot resolve the destination host's domain name to find its | 
					
						
							|  |  |  | # IP address, it should set the first three bytes of DSTIP to NULL and the last | 
					
						
							|  |  |  | # byte to a non-zero value. | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  | SOCKS4_DEFAULT_DSTIP = compat_struct_pack('!BBBB', 0, 0, 0, 0xFF) | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | SOCKS5_VERSION = 5 | 
					
						
							|  |  |  | SOCKS5_USER_AUTH_VERSION = 0x01 | 
					
						
							|  |  |  | SOCKS5_USER_AUTH_SUCCESS = 0x00 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Socks4Command(object): | 
					
						
							|  |  |  |     CMD_CONNECT = 0x01 | 
					
						
							|  |  |  |     CMD_BIND = 0x02 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Socks5Command(Socks4Command): | 
					
						
							|  |  |  |     CMD_UDP_ASSOCIATE = 0x03 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Socks5Auth(object): | 
					
						
							|  |  |  |     AUTH_NONE = 0x00 | 
					
						
							|  |  |  |     AUTH_GSSAPI = 0x01 | 
					
						
							|  |  |  |     AUTH_USER_PASS = 0x02 | 
					
						
							|  |  |  |     AUTH_NO_ACCEPTABLE = 0xFF  # For server response | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Socks5AddressType(object): | 
					
						
							|  |  |  |     ATYP_IPV4 = 0x01 | 
					
						
							|  |  |  |     ATYP_DOMAINNAME = 0x03 | 
					
						
							|  |  |  |     ATYP_IPV6 = 0x04 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-05 00:31:02 +08:00
										 |  |  | class ProxyError(socket.error): | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |     ERR_SUCCESS = 0x00 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, code=None, msg=None): | 
					
						
							|  |  |  |         if code is not None and msg is None: | 
					
						
							| 
									
										
										
										
											2016-12-03 21:53:41 +08:00
										 |  |  |             msg = self.CODES.get(code) or 'unknown error' | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         super(ProxyError, self).__init__(code, msg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class InvalidVersionError(ProxyError): | 
					
						
							|  |  |  |     def __init__(self, expected_version, got_version): | 
					
						
							|  |  |  |         msg = ('Invalid response version from server. Expected {0:02x} got ' | 
					
						
							|  |  |  |                '{1:02x}'.format(expected_version, got_version)) | 
					
						
							|  |  |  |         super(InvalidVersionError, self).__init__(0, msg) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Socks4Error(ProxyError): | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |     ERR_SUCCESS = 90 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |     CODES = { | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         91: 'request rejected or failed', | 
					
						
							| 
									
										
										
										
											2016-06-26 01:23:48 +07:00
										 |  |  |         92: 'request rejected because SOCKS server cannot connect to identd on the client', | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         93: 'request rejected because the client program and identd report different user-ids' | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  | class Socks5Error(ProxyError): | 
					
						
							|  |  |  |     ERR_GENERAL_FAILURE = 0x01 | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |     CODES = { | 
					
						
							|  |  |  |         0x01: 'general SOCKS server failure', | 
					
						
							|  |  |  |         0x02: 'connection not allowed by ruleset', | 
					
						
							|  |  |  |         0x03: 'Network unreachable', | 
					
						
							|  |  |  |         0x04: 'Host unreachable', | 
					
						
							|  |  |  |         0x05: 'Connection refused', | 
					
						
							|  |  |  |         0x06: 'TTL expired', | 
					
						
							|  |  |  |         0x07: 'Command not supported', | 
					
						
							|  |  |  |         0x08: 'Address type not supported', | 
					
						
							|  |  |  |         0xFE: 'unknown username or invalid password', | 
					
						
							|  |  |  |         0xFF: 'all offered authentication methods were rejected' | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class ProxyType(object): | 
					
						
							|  |  |  |     SOCKS4 = 0 | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |     SOCKS4A = 1 | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  |     SOCKS5 = 2 | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-17 19:42:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  | Proxy = collections.namedtuple('Proxy', ( | 
					
						
							|  |  |  |     'type', 'host', 'port', 'username', 'password', 'remote_dns')) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  | class sockssocket(socket.socket): | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |     def __init__(self, *args, **kwargs): | 
					
						
							|  |  |  |         self._proxy = None | 
					
						
							|  |  |  |         super(sockssocket, self).__init__(*args, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setproxy(self, proxytype, addr, port, rdns=True, username=None, password=None): | 
					
						
							|  |  |  |         assert proxytype in (ProxyType.SOCKS4, ProxyType.SOCKS4A, ProxyType.SOCKS5) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self._proxy = Proxy(proxytype, addr, port, username, password, rdns) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def recvall(self, cnt): | 
					
						
							|  |  |  |         data = b'' | 
					
						
							|  |  |  |         while len(data) < cnt: | 
					
						
							|  |  |  |             cur = self.recv(cnt - len(data)) | 
					
						
							|  |  |  |             if not cur: | 
					
						
							| 
									
										
										
										
											2016-12-05 00:31:02 +08:00
										 |  |  |                 raise EOFError('{0} bytes missing'.format(cnt - len(data))) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |             data += cur | 
					
						
							|  |  |  |         return data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |     def _recv_bytes(self, cnt): | 
					
						
							|  |  |  |         data = self.recvall(cnt) | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |         return compat_struct_unpack('!{0}B'.format(cnt), data) | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def _len_and_data(data): | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |         return compat_struct_pack('!B', len(data)) + data | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _check_response_version(self, expected_version, got_version): | 
					
						
							|  |  |  |         if got_version != expected_version: | 
					
						
							|  |  |  |             self.close() | 
					
						
							|  |  |  |             raise InvalidVersionError(expected_version, got_version) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |     def _resolve_address(self, destaddr, default, use_remote_dns): | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |             return socket.inet_aton(destaddr) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |         except socket.error: | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |             if use_remote_dns and self._proxy.remote_dns: | 
					
						
							|  |  |  |                 return default | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |                 return socket.inet_aton(socket.gethostbyname(destaddr)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _setup_socks4(self, address, is_4a=False): | 
					
						
							|  |  |  |         destaddr, port = address | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ipaddr = self._resolve_address(destaddr, SOCKS4_DEFAULT_DSTIP, use_remote_dns=is_4a) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |         packet = compat_struct_pack('!BBH', SOCKS4_VERSION, Socks4Command.CMD_CONNECT, port) + ipaddr | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         username = (self._proxy.username or '').encode('utf-8') | 
					
						
							|  |  |  |         packet += username + b'\x00' | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if is_4a and self._proxy.remote_dns: | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |             packet += destaddr.encode('utf-8') + b'\x00' | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.sendall(packet) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |         version, resp_code, dstport, dsthost = compat_struct_unpack('!BBHI', self.recvall(8)) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         self._check_response_version(SOCKS4_REPLY_VERSION, version) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         if resp_code != Socks4Error.ERR_SUCCESS: | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |             self.close() | 
					
						
							|  |  |  |             raise Socks4Error(resp_code) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  |         return (dsthost, dstport) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |     def _setup_socks4a(self, address): | 
					
						
							|  |  |  |         self._setup_socks4(address, is_4a=True) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |     def _socks5_auth(self): | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |         packet = compat_struct_pack('!B', SOCKS5_VERSION) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         auth_methods = [Socks5Auth.AUTH_NONE] | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |         if self._proxy.username and self._proxy.password: | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |             auth_methods.append(Socks5Auth.AUTH_USER_PASS) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |         packet += compat_struct_pack('!B', len(auth_methods)) | 
					
						
							|  |  |  |         packet += compat_struct_pack('!{0}B'.format(len(auth_methods)), *auth_methods) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.sendall(packet) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         version, method = self._recv_bytes(2) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         self._check_response_version(SOCKS5_VERSION, version) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-22 21:44:01 +08:00
										 |  |  |         if method == Socks5Auth.AUTH_NO_ACCEPTABLE or ( | 
					
						
							|  |  |  |                 method == Socks5Auth.AUTH_USER_PASS and (not self._proxy.username or not self._proxy.password)): | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |             self.close() | 
					
						
							| 
									
										
										
										
											2017-04-22 21:44:01 +08:00
										 |  |  |             raise Socks5Error(Socks5Auth.AUTH_NO_ACCEPTABLE) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         if method == Socks5Auth.AUTH_USER_PASS: | 
					
						
							|  |  |  |             username = self._proxy.username.encode('utf-8') | 
					
						
							|  |  |  |             password = self._proxy.password.encode('utf-8') | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |             packet = compat_struct_pack('!B', SOCKS5_USER_AUTH_VERSION) | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |             packet += self._len_and_data(username) + self._len_and_data(password) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |             self.sendall(packet) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |             version, status = self._recv_bytes(2) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |             self._check_response_version(SOCKS5_USER_AUTH_VERSION, version) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |             if status != SOCKS5_USER_AUTH_SUCCESS: | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |                 self.close() | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |                 raise Socks5Error(Socks5Error.ERR_GENERAL_FAILURE) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |     def _setup_socks5(self, address): | 
					
						
							|  |  |  |         destaddr, port = address | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ipaddr = self._resolve_address(destaddr, None, use_remote_dns=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self._socks5_auth() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         reserved = 0 | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |         packet = compat_struct_pack('!BBB', SOCKS5_VERSION, Socks5Command.CMD_CONNECT, reserved) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |         if ipaddr is None: | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |             destaddr = destaddr.encode('utf-8') | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |             packet += compat_struct_pack('!B', Socks5AddressType.ATYP_DOMAINNAME) | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |             packet += self._len_and_data(destaddr) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |             packet += compat_struct_pack('!B', Socks5AddressType.ATYP_IPV4) + ipaddr | 
					
						
							|  |  |  |         packet += compat_struct_pack('!H', port) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.sendall(packet) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         version, status, reserved, atype = self._recv_bytes(4) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         self._check_response_version(SOCKS5_VERSION, version) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         if status != Socks5Error.ERR_SUCCESS: | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |             self.close() | 
					
						
							|  |  |  |             raise Socks5Error(status) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         if atype == Socks5AddressType.ATYP_IPV4: | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |             destaddr = self.recvall(4) | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         elif atype == Socks5AddressType.ATYP_DOMAINNAME: | 
					
						
							|  |  |  |             alen = compat_ord(self.recv(1)) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |             destaddr = self.recvall(alen) | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         elif atype == Socks5AddressType.ATYP_IPV6: | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |             destaddr = self.recvall(16) | 
					
						
							| 
									
										
										
										
											2016-05-03 16:50:16 +08:00
										 |  |  |         destport = compat_struct_unpack('!H', self.recvall(2))[0] | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return (destaddr, destport) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _make_proxy(self, connect_func, address): | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         if not self._proxy: | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |             return connect_func(self, address) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 15:11:05 +08:00
										 |  |  |         result = connect_func(self, (self._proxy.host, self._proxy.port)) | 
					
						
							|  |  |  |         if result != 0 and result is not None: | 
					
						
							|  |  |  |             return result | 
					
						
							|  |  |  |         setup_funcs = { | 
					
						
							|  |  |  |             ProxyType.SOCKS4: self._setup_socks4, | 
					
						
							|  |  |  |             ProxyType.SOCKS4A: self._setup_socks4a, | 
					
						
							|  |  |  |             ProxyType.SOCKS5: self._setup_socks5, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         setup_funcs[self._proxy.type](address) | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  |     def connect(self, address): | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  |         self._make_proxy(socket.socket.connect, address) | 
					
						
							| 
									
										
										
										
											2016-04-23 15:44:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def connect_ex(self, address): | 
					
						
							| 
									
										
										
										
											2016-04-23 21:30:06 +08:00
										 |  |  |         return self._make_proxy(socket.socket.connect_ex, address) |