LoginSignup
0
0

More than 3 years have passed since last update.

Enabling pysocks proxy RDNS globally

Last updated at Posted at 2020-02-13

Usually, they say that overriding socket.socket will make socks proxy usable on any python libraries:

import socks
import socket
socks.set_default_proxy(socks.PROXY_TYPE_SOCKS5, "host", port)
socket.socket = socks.socksocket

However, it would not work well if the machine you want to connect can be connected only from the proxy (i.e. when RDNS is mandatory). This is because socket.create_connection() always resolves the machine's ip address locally:
(cf https://github.com/python/cpython/blob/2.7/Lib/socket.py#L557)


    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

So, if we need RDNS, create_connection needs to be wrapped as well:

_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
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0