PySocks icon indicating copy to clipboard operation
PySocks copied to clipboard

wrapmodule affects not just the wrapped module

Open CyberShadow opened this issue 4 years ago • 2 comments

wrapmodule is defined simply as:

https://github.com/Anorov/PySocks/blob/c2fa43cbe1091e799e248e8e4433978916791a8b/socks.py#L146

However, that will affect not just the socket function as it is visible from the module, but from everywhele else as well. Therefore, e.g. socks.wrapmodule(smtplib) will affect the entire application.

CyberShadow avatar Jan 08 '22 17:01 CyberShadow

Same issue here. Is there any other method to wrap a single module ?

PhilipGarnero avatar Mar 03 '25 15:03 PhilipGarnero

I've figured out something :

class PatchedSocketModule:
    def __init__(self, proxy_type, proxy_host, proxy_port, proxy_user, proxy_password):
        """
        Initialize an SMTP proxy configuration container.

        Args:
            proxy_type (str): Type of proxy (e.g., 'http', 'socks4', 'socks5')
            proxy_host (str): Hostname or IP address of the proxy server
            proxy_port (int): Port number for the proxy server
            proxy_user (str): Username for proxy authentication (optional)
            proxy_password (str): Password for proxy authentication (optional)
        """
        self.proxy_type = proxy_type
        self.proxy_host = proxy_host
        self.proxy_port = proxy_port
        self.proxy_user = proxy_user
        self.proxy_password = proxy_password

    def create_connection_patched(self, *args, **kwargs):
        """Patched version of socket.create_connection that routes through proxy."""
        return socks.create_connection(
            *args, **kwargs,
            proxy_type=self.proxy_type,
            proxy_addr=self.proxy_host,
            proxy_port=self.proxy_port,
            proxy_username=self.proxy_user,
            proxy_password=self.proxy_password,
        )

    def __getattr__(self, name):
        if name == 'socket':
            return socks.socksocket
        if name == 'create_connection':
            return self.create_connection_patched
        return getattr(socket, name)


def configure_smtp_proxy(proxy_type, proxy_host, proxy_port, proxy_user, proxy_password):
    """Configures the global SMTP proxy settings."""
    if not hasattr(configure_smtp_proxy, 'configured'):
        socks.setdefaultproxy(proxy_type, proxy_host, proxy_port, username=proxy_user, password=proxy_password)
        p = patch('smtplib.socket', PatchedSocketModule(proxy_type, proxy_host, proxy_port, proxy_user, proxy_password))
        p.start()
        configure_smtp_proxy.configured = True

It's not pretty but it works

PhilipGarnero avatar Mar 04 '25 18:03 PhilipGarnero