Anorov / PySocks

A SOCKS proxy client and wrapper for Python.
Other
1.23k stars 258 forks source link

sockshandler.py may need a little update #134

Open tigerzhou100800 opened 4 years ago

tigerzhou100800 commented 4 years ago

New Python3 When create opener this way :

import urllib.request as urllib2
import socks
from sockshandler import SocksiPyHandler

opener = urllib2.build_opener(SocksiPyHandler(socks.SOCKS5, "127.0.0.1", 9050))

source code sockshandler.py line 49, self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) Will cause SNI(server name indication) missing , that cloudflare cdn may 403 error or blank page. Multi sites host on same ip need SNI to tell apart request to which.

https://docs.python.org/3.7/library/ssl.html#ssl.wrap_socket

Deprecated since version 3.7: Since Python 3.2 and 2.7.9, it is recommended to use the SSLContext.wrap_socket() instead of wrap_socket(). The top-level function is limited and creates an insecure client socket without server name indication or hostname matching.

Hotfix: mod this class

class SocksiPyConnectionS(httplib.HTTPSConnection):
    def __init__(self, proxytype, proxyaddr, proxyport=None, rdns=True, username=None, password=None, *args, **kwargs):
        self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password)
        httplib.HTTPSConnection.__init__(self, *args, **kwargs)

    def connect(self):
        sock = socks.socksocket()
        sock.setproxy(*self.proxyargs)
        if type(self.timeout) in (int, float):
            sock.settimeout(self.timeout)
        sock.connect((self.host, self.port))
        self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)

to this

class SocksiPyConnectionS(httplib.HTTPSConnection):
    def __init__(self, proxytype, proxyaddr, proxyport=None, rdns=True, username=None, password=None, *args, **kwargs):
        self.context = ssl.create_default_context()
        self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password)
        httplib.HTTPSConnection.__init__(self, *args, **kwargs)

    def connect(self):
        sock = socks.socksocket()
        sock.setproxy(*self.proxyargs)
        if type(self.timeout) in (int, float):
            sock.settimeout(self.timeout)
        sock.connect((self.host, self.port))
        self.sock = self.context.wrap_socket(sock,server_hostname=self.host)
SeaHOH commented 4 years ago

See #133 , you need the 1.7.1 version.

tigerzhou100800 commented 4 years ago

Haaa Sorry, my bad.

SeaHOH commented 4 years ago

sock.setproxy(*self.proxyargs) equivalent to sock.set_proxy(*self.proxyargs) in any case, and self.proxy = also equivalent to socksocket.proxy = if use only one proxy server.

I think you could re-compare original with your patched 1.7.0.

SeaHOH commented 4 years ago

I found a issue, only from python 32 to 36, class HTTPSConnection has _check_hostname attribute.

tigerzhou100800 commented 4 years ago

My bad.

SeaHOH commented 4 years ago

I have found the issue, self.proxy = is not equivalent to socksocket.proxy =.

import socks
socks.socksocket.proxy = 'something'
sock = socks.socksocket()
print(sock.proxy)  # (None, None, None, None, None, None)

In fact, you directed open req without via proxy server.

tigerzhou100800 commented 4 years ago

I have found the issue, self.proxy = is not equivalent to socksocket.proxy =.

import socks
socks.socksocket.proxy = 'something'
sock = socks.socksocket()
print(sock.proxy)  # (None, None, None, None, None, None)

In fact, you directed open req without via proxy server.

Yes, that two fix I posted before are all wrong. First one doesn't change any in my proxy setting , because I didn't use keyword args. Second one as you point out , It just didn't via proxy at all. Thinking first one changes any , was the socks4 proxy that I used was unstable.

Socks4 with no bug. What I posted before it's mistake. It was all about remote dns. Here was what happened : The site I tested is filtered dns resolve by my ISP, direct dns that site will block IP, and via proxy dns also block IP. I changed my system local hosts file to static resolve that site . When I use socks.set_default_proxy It didn't set remote dns to True (whether your set rdns True of False , doesn't work, see next reply ). I wrote a socks5 python script , it received host IP addrs when I use socks.set_default_proxy . So connected to the test site OK. When use opener , it realy did remote dns resolve, causing IP blocked by my ISP . So it wasn't PySocks wrong. When change sockshandler.py rdns to False , socks4 works fine. And socks5 I tested before , was using my socks5 script , it does dns resolve via dnscrypt, so didn't got blocked.

tigerzhou100800 commented 4 years ago

Didn't test python2, here tested in python3.

import urllib.request as urllib2
import socket
import socks

socks.set_default_proxy(socks.SOCKS5, "localhost")
socket.socket = socks.socksocket

Whether your set rdns

socks.set_default_proxy(socks.SOCKS5,"127.0.0.1", 7071, True)
socks.set_default_proxy(socks.SOCKS5,"127.0.0.1", 7071, False)

same pdb result

python 3.6.7   c:\python36\lib\socket.py(713)create_connection()
702         host, port = address   #  It's hostname here
703         err = None
704         for res in getaddrinfo(host, port, 0, SOCK_STREAM):
705             af, socktype, proto, canonname, sa = res     #   After getaddrinfo reture res ,  sa in res already resolve to hostip .  For example ('141.101.120.54', 443)
706             sock = None
707             try:
708                 sock = socket(af, socktype, proto)
709                 if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
710                     sock.settimeout(timeout)
711                 if source_address:
712                     sock.bind(source_address)
713  ->             sock.connect(sa)    #   This call  socks.py  of PySocks

socks.py receive request in ip form, already resolve dns . No DNS work left to socks.py

SeaHOH commented 4 years ago

Whether your set rdns

socks.set_default_proxy(socks.SOCKS5, "localhost", True)
socks.set_default_proxy(socks.SOCKS5, "localhost", False)

should be

socks.set_default_proxy(socks.SOCKS5, "localhost", rdns=True)
socks.set_default_proxy(socks.SOCKS5, "localhost", rdns=False)
# use default port 1080

or

socks.set_default_proxy(socks.SOCKS5, "localhost", your_port, True)
socks.set_default_proxy(socks.SOCKS5, "localhost", your_port, False)
tigerzhou100800 commented 4 years ago

Whether your set rdns

socks.set_default_proxy(socks.SOCKS5, "localhost", True)
socks.set_default_proxy(socks.SOCKS5, "localhost", False)

should be

socks.set_default_proxy(socks.SOCKS5, "localhost", rdns=True)
socks.set_default_proxy(socks.SOCKS5, "localhost", rdns=False)
# use default port 1080

or

socks.set_default_proxy(socks.SOCKS5, "localhost", your_port, True)
socks.set_default_proxy(socks.SOCKS5, "localhost", your_port, False)

See the old post, about dns. https://github.com/Anorov/PySocks/issues/22

SeaHOH commented 4 years ago

Forget #22, if you do not use socket directly. If you want to use urllib.request.OpenerDirector, sockshandler has provided, do socket.socket = socks.socksocket has no effect; if you want to create a new connection, use socks.create_connection, not the socket.create_connection.

nil0x42 commented 1 year ago

already 3 years have passed, and now it looks like sockshandler doesn't work anymore on python 3.10.

I've receive an issue on my repo: https://github.com/nil0x42/phpsploit/issues/194

It's frustrating, i'll have to make a copy of the lib patched by https://github.com/Anorov/PySocks/pull/135 instead of waiting for a proper release.

@Anorov , would you kindly consider merging pull requests ?

SeaHOH commented 1 year ago

@nil0x42 The maintenance has been stopped. Maybe ExtProxy ( an alternate for sockshandler.py ) can help you.

nil0x42 commented 1 year ago

Thank you @SeaHOH !