From 39e323e1f0d093d5e8e971536585600f6c508074 Mon Sep 17 00:00:00 2001 From: SeaHOH Date: Fri, 29 Nov 2019 10:31:20 +0800 Subject: [PATCH 1/6] bugfix & improve 1. Fixed `socksocket.connect` not be correct for catch `ProxyError` when run in python 3. 2. Disable rdns by default when sockshandler use SOCKS4. 3. Improve on sockshandler's code. --- socks.py | 8 ++--- sockshandler.py | 86 +++++++++++++++++++++++++++++-------------------- 2 files changed, 55 insertions(+), 39 deletions(-) diff --git a/socks.py b/socks.py index 83b1435..c7aa0b0 100644 --- a/socks.py +++ b/socks.py @@ -807,6 +807,10 @@ def connect(self, dest_pair, catch_errors=None): # Calls negotiate_{SOCKS4, SOCKS5, HTTP} negotiate = self._proxy_negotiators[proxy_type] negotiate(self, dest_addr, dest_port) + except ProxyError: + # Protocol error while negotiating with proxy + self.close() + raise except socket.error as error: if not catch_errors: # Wrap socket errors @@ -814,10 +818,6 @@ def connect(self, dest_pair, catch_errors=None): raise GeneralProxyError("Socket error", error) else: raise error - except ProxyError: - # Protocol error while negotiating with proxy - self.close() - raise @set_self_blocking def connect_ex(self, dest_pair): diff --git a/sockshandler.py b/sockshandler.py index 6a2ed81..8cf2caa 100644 --- a/sockshandler.py +++ b/sockshandler.py @@ -9,6 +9,7 @@ """ import socket import ssl +import time try: import urllib2 @@ -19,10 +20,6 @@ import socks # $ pip install PySocks -def merge_dict(a, b): - d = a.copy() - d.update(b) - return d def is_ip(s): try: @@ -40,65 +37,84 @@ def is_ip(s): socks4_no_rdns = set() class SocksiPyConnection(httplib.HTTPConnection): - def __init__(self, proxytype, proxyaddr, proxyport=None, rdns=True, username=None, password=None, *args, **kwargs): - self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password) - httplib.HTTPConnection.__init__(self, *args, **kwargs) + def __init__(self, host, proxytype, proxyaddr, proxyport=None, rdns=None, username=None, password=None, **kwargs): + self.proxyargs = proxytype, proxyaddr, proxyport, rdns, username, password + httplib.HTTPConnection.__init__(self, host, **kwargs) def connect(self): - (proxytype, proxyaddr, proxyport, rdns, username, password) = self.proxyargs - rdns = rdns and proxyaddr not in socks4_no_rdns - while True: + proxytype, proxyaddr, proxyport, rdns, username, password = self.proxyargs + if rdns is None: + # SOCKS4 disable rdns by default + rdns = proxytype is not socks.SOCKS4 + if rdns: + rdns = proxyaddr not in socks4_no_rdns + + try_num = 3 if rdns and proxytype is socks.SOCKS4 else 2 + rest = 3 + ex = None + sock = None + + for i in range(try_num): try: sock = socks.create_connection( (self.host, self.port), self.timeout, None, - proxytype, proxyaddr, proxyport, rdns, username, password, - ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),)) + proxytype, proxyaddr, proxyport, rdns, username, password) break except socks.SOCKS4Error as e: - if rdns and "0x5b" in str(e) and not is_ip(self.host): + ex = e + if rdns and e.msg[:4] == "0x5b" and not is_ip(self.host): # Maybe a SOCKS4 server that doesn't support remote resolving - # Let's try again + # Disable rdns and try again rdns = False socks4_no_rdns.add(proxyaddr) else: - raise + raise e + except socks.GeneralProxyError as e: + ex = e + if e.msg != "Connection closed unexpectedly": + raise e + except socks.ProxyConnectionError as e: + ex = e + + # Need a rest befor retry + if i + 1 < try_num: + time.sleep(rest) + + if sock is None: + raise ex self.sock = sock 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 __init__(self, host, proxytype, proxyaddr, proxyport=None, rdns=True, username=None, password=None, **kwargs): + self.proxyargs = proxytype, proxyaddr, proxyport, rdns, username, password + httplib.HTTPSConnection.__init__(self, host, **kwargs) def connect(self): + # Attribute `_check_hostname` used in python 3.2 to 3.6 + check_hostname = getattr(self, "_check_hostname", None) + if check_hostname: + self._context.check_hostname = check_hostname SocksiPyConnection.connect(self) self.sock = self._context.wrap_socket(self.sock, server_hostname=self.host) - if not self._context.check_hostname and self._check_hostname: - try: - ssl.match_hostname(self.sock.getpeercert(), self.host) - except Exception: - self.sock.shutdown(socket.SHUT_RDWR) - self.sock.close() - raise class SocksiPyHandler(urllib2.HTTPHandler, urllib2.HTTPSHandler): def __init__(self, *args, **kwargs): + debuglevel = kwargs.pop("debuglevel", 0) self.args = args - self.kw = kwargs - urllib2.HTTPHandler.__init__(self) + self.kwargs = kwargs + urllib2.HTTPSHandler.__init__(self, debuglevel=debuglevel) def http_open(self, req): - def build(host, port=None, timeout=0, **kwargs): - kw = merge_dict(self.kw, kwargs) - conn = SocksiPyConnection(*self.args, host=host, port=port, timeout=timeout, **kw) + def build(host, **kwargs): + conn = SocksiPyConnection(host, *self.args, **kwargs) return conn - return self.do_open(build, req) + return self.do_open(build, req, **self.kwargs) def https_open(self, req): - def build(host, port=None, timeout=0, **kwargs): - kw = merge_dict(self.kw, kwargs) - conn = SocksiPyConnectionS(*self.args, host=host, port=port, timeout=timeout, **kw) + def build(host, **kwargs): + conn = SocksiPyConnectionS(host, *self.args, **kwargs) return conn - return self.do_open(build, req) + return self.do_open(build, req, **self.kwargs) if __name__ == "__main__": import sys From 938f699c1e6ad0f0678905fb027f98a463315a83 Mon Sep 17 00:00:00 2001 From: SeaHOH Date: Fri, 29 Nov 2019 10:46:21 +0800 Subject: [PATCH 2/6] Update sockshandler.py --- sockshandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sockshandler.py b/sockshandler.py index 8cf2caa..4e0bad1 100644 --- a/sockshandler.py +++ b/sockshandler.py @@ -85,7 +85,7 @@ def connect(self): self.sock = sock class SocksiPyConnectionS(httplib.HTTPSConnection): - def __init__(self, host, proxytype, proxyaddr, proxyport=None, rdns=True, username=None, password=None, **kwargs): + def __init__(self, host, proxytype, proxyaddr, proxyport=None, rdns=None, username=None, password=None, **kwargs): self.proxyargs = proxytype, proxyaddr, proxyport, rdns, username, password httplib.HTTPSConnection.__init__(self, host, **kwargs) From 314c4fe99f76481f4ab28dc735d97e2640421fd1 Mon Sep 17 00:00:00 2001 From: SeaHOH Date: Sat, 30 Nov 2019 05:53:30 +0800 Subject: [PATCH 3/6] update --- sockshandler.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sockshandler.py b/sockshandler.py index 4e0bad1..fbd8e8a 100644 --- a/sockshandler.py +++ b/sockshandler.py @@ -37,8 +37,8 @@ def is_ip(s): socks4_no_rdns = set() class SocksiPyConnection(httplib.HTTPConnection): - def __init__(self, host, proxytype, proxyaddr, proxyport=None, rdns=None, username=None, password=None, **kwargs): - self.proxyargs = proxytype, proxyaddr, proxyport, rdns, username, password + def __init__(self, proxyargs, host, **kwargs): + self.proxyargs = proxyargs httplib.HTTPConnection.__init__(self, host, **kwargs) def connect(self): @@ -57,8 +57,8 @@ def connect(self): for i in range(try_num): try: sock = socks.create_connection( - (self.host, self.port), self.timeout, None, - proxytype, proxyaddr, proxyport, rdns, username, password) + (self.host, self.port), self.timeout, None, + proxytype, proxyaddr, proxyport, rdns, username, password) break except socks.SOCKS4Error as e: ex = e @@ -85,8 +85,8 @@ def connect(self): self.sock = sock class SocksiPyConnectionS(httplib.HTTPSConnection): - def __init__(self, host, proxytype, proxyaddr, proxyport=None, rdns=None, username=None, password=None, **kwargs): - self.proxyargs = proxytype, proxyaddr, proxyport, rdns, username, password + def __init__(self, proxyargs, host, **kwargs): + self.proxyargs = proxyargs httplib.HTTPSConnection.__init__(self, host, **kwargs) def connect(self): @@ -97,22 +97,22 @@ def connect(self): SocksiPyConnection.connect(self) self.sock = self._context.wrap_socket(self.sock, server_hostname=self.host) -class SocksiPyHandler(urllib2.HTTPHandler, urllib2.HTTPSHandler): - def __init__(self, *args, **kwargs): - debuglevel = kwargs.pop("debuglevel", 0) - self.args = args +class SocksiPyHandler(urllib2.ProxyHandler, urllib2.HTTPHandler, urllib2.HTTPSHandler): + def __init__(self, proxytype, proxyaddr, proxyport=None, rdns=None, + username=None, password=None, debuglevel=0, **kwargs): + self.proxyargs = proxytype, proxyaddr, proxyport, rdns, username, password self.kwargs = kwargs urllib2.HTTPSHandler.__init__(self, debuglevel=debuglevel) def http_open(self, req): def build(host, **kwargs): - conn = SocksiPyConnection(host, *self.args, **kwargs) + conn = SocksiPyConnection(self.proxyargs, host, **kwargs) return conn return self.do_open(build, req, **self.kwargs) def https_open(self, req): def build(host, **kwargs): - conn = SocksiPyConnectionS(host, *self.args, **kwargs) + conn = SocksiPyConnectionS(self.proxyargs, host, **kwargs) return conn return self.do_open(build, req, **self.kwargs) From cf2b9d012c0750219f4f2babe95e6149eb2b5372 Mon Sep 17 00:00:00 2001 From: SeaHOH Date: Sun, 1 Dec 2019 12:20:18 +0800 Subject: [PATCH 4/6] update --- sockshandler.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sockshandler.py b/sockshandler.py index fbd8e8a..3a170c0 100644 --- a/sockshandler.py +++ b/sockshandler.py @@ -21,14 +21,9 @@ import socks # $ pip install PySocks -def is_ip(s): +def is_ipv4(s): try: - if ':' in s: - socket.inet_pton(socket.AF_INET6, s) - elif '.' in s: - socket.inet_aton(s) - else: - return False + socket.inet_aton(s) except: return False else: @@ -62,7 +57,7 @@ def connect(self): break except socks.SOCKS4Error as e: ex = e - if rdns and e.msg[:4] == "0x5b" and not is_ip(self.host): + if rdns and e.msg[:4] == "0x5b" and not is_ipv4(self.host): # Maybe a SOCKS4 server that doesn't support remote resolving # Disable rdns and try again rdns = False From 36b33de2238a07eb82018b5ad006d0dd1d3e0406 Mon Sep 17 00:00:00 2001 From: SeaHOH Date: Mon, 2 Dec 2019 08:36:16 +0800 Subject: [PATCH 5/6] Update sockshandler.py --- sockshandler.py | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/sockshandler.py b/sockshandler.py index 3a170c0..d508047 100644 --- a/sockshandler.py +++ b/sockshandler.py @@ -9,7 +9,6 @@ """ import socket import ssl -import time try: import urllib2 @@ -43,20 +42,15 @@ def connect(self): rdns = proxytype is not socks.SOCKS4 if rdns: rdns = proxyaddr not in socks4_no_rdns - - try_num = 3 if rdns and proxytype is socks.SOCKS4 else 2 - rest = 3 - ex = None - sock = None - for i in range(try_num): + while True: try: sock = socks.create_connection( (self.host, self.port), self.timeout, None, - proxytype, proxyaddr, proxyport, rdns, username, password) + proxytype, proxyaddr, proxyport, rdns, username, password, + ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),)) break except socks.SOCKS4Error as e: - ex = e if rdns and e.msg[:4] == "0x5b" and not is_ipv4(self.host): # Maybe a SOCKS4 server that doesn't support remote resolving # Disable rdns and try again @@ -64,19 +58,7 @@ def connect(self): socks4_no_rdns.add(proxyaddr) else: raise e - except socks.GeneralProxyError as e: - ex = e - if e.msg != "Connection closed unexpectedly": - raise e - except socks.ProxyConnectionError as e: - ex = e - - # Need a rest befor retry - if i + 1 < try_num: - time.sleep(rest) - if sock is None: - raise ex self.sock = sock class SocksiPyConnectionS(httplib.HTTPSConnection): From cadeb720a79cff64068c9932d586e6660d4e0c85 Mon Sep 17 00:00:00 2001 From: SeaHOH Date: Mon, 2 Dec 2019 08:45:24 +0800 Subject: [PATCH 6/6] Update sockshandler.py --- sockshandler.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sockshandler.py b/sockshandler.py index d508047..24a9a7a 100644 --- a/sockshandler.py +++ b/sockshandler.py @@ -41,11 +41,11 @@ def connect(self): # SOCKS4 disable rdns by default rdns = proxytype is not socks.SOCKS4 if rdns: - rdns = proxyaddr not in socks4_no_rdns + rdns = (proxyaddr, proxyport) not in socks4_no_rdns while True: try: - sock = socks.create_connection( + self.sock = socks.create_connection( (self.host, self.port), self.timeout, None, proxytype, proxyaddr, proxyport, rdns, username, password, ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),)) @@ -55,12 +55,10 @@ def connect(self): # Maybe a SOCKS4 server that doesn't support remote resolving # Disable rdns and try again rdns = False - socks4_no_rdns.add(proxyaddr) + socks4_no_rdns.add((proxyaddr, proxyport)) else: raise e - self.sock = sock - class SocksiPyConnectionS(httplib.HTTPSConnection): def __init__(self, proxyargs, host, **kwargs): self.proxyargs = proxyargs