通常,他们说重写socket.socket将使socks代理可在任何python库中使用:
1 2 3 4 | import socks import socket socks.set_default_proxy(socks.PROXY_TYPE_SOCKS5, "host", port) socket.socket = socks.socksocket |
但是,如果要连接的计算机只能通过代理连接(即必须使用RDNS),则无法正常工作,这是因为socket.create_connection()始终在本地解析该计算机的IP地址:
(cf https://github.com/python/cpython/blob/2.7/Lib/socket.py#L557)
1 2 3 4 5 6 7 8 | host, port = address for res in getaddrinfo(host, port, 0, SOCK_STREAM): af, socktype, proto, canonname, sa = res ### sa is resolved locally! sock = None try: sock = socket(af, socktype, proto) ### this socket is overridden by socks.socksocket, but RDNS will not work well. sock.connect(sa) return sock |
因此,如果我们需要RDNS,则create_connection也需要包装:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | _done_tryPatchCreateConnections = False def tryPatchCreateConnections(): global _done_tryPatchCreateConnections if _done_tryPatchCreateConnections: return True try: import socks import socket socket.socket = socks.socksocket def patchCreateConnection(module): def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None, socket_options=None): #print('trying to override create_connection') if socks.socksocket.default_proxy is not None and socks.socksocket.default_proxy[3]: return socks.create_connection( address, timeout=timeout, source_address=source_address, proxy_type=socks.socksocket.default_proxy[0], proxy_addr=socks.socksocket.default_proxy[1], proxy_port=socks.socksocket.default_proxy[2], proxy_rdns=socks.socksocket.default_proxy[3], proxy_username=socks.socksocket.default_proxy[4], proxy_password=socks.socksocket.default_proxy[5], socket_options=socket_options, ) elif module==socket: return module._real_create_connection(address, timeout=timeout, source_address=source_address) else: # likely urllib3 return module._real_create_connection(address, timeout=timeout, source_address=source_address, socket_options=socket_options) module._real_create_connection = module.create_connection module.create_connection = create_connection module.socket = socks.socksocket def patchCreateConnections(): patchCreateConnection(socket) try: import urllib3 patchCreateConnection(urllib3.util.connection) except ImportError: pass try: import requests import requests.packages.urllib3 patchCreateConnection(requests.packages.urllib3.util.connection) except ImportError: pass patchCreateConnections() _done_tryPatchCreateConnections = True return True except ImportError: return False |