sockshandler.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #!/usr/bin/env python
  2. """
  3. SocksiPy + urllib2 handler
  4. version: 0.3
  5. author: e<e@tr0ll.in>
  6. This module provides a Handler which you can use with urllib2 to allow it to tunnel your connection through a socks.sockssocket socket, with out monkey patching the original socket...
  7. """
  8. import socket
  9. import ssl
  10. try:
  11. import urllib2
  12. import httplib
  13. except ImportError: # Python 3
  14. import urllib.request as urllib2
  15. import http.client as httplib
  16. import socks # $ pip install PySocks
  17. def merge_dict(a, b):
  18. d = a.copy()
  19. d.update(b)
  20. return d
  21. def is_ip(s):
  22. try:
  23. if ':' in s:
  24. socket.inet_pton(socket.AF_INET6, s)
  25. elif '.' in s:
  26. socket.inet_aton(s)
  27. else:
  28. return False
  29. except:
  30. return False
  31. else:
  32. return True
  33. socks4_no_rdns = set()
  34. class SocksiPyConnection(httplib.HTTPConnection):
  35. def __init__(self, proxytype, proxyaddr, proxyport=None, rdns=True, username=None, password=None, *args, **kwargs):
  36. self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password)
  37. httplib.HTTPConnection.__init__(self, *args, **kwargs)
  38. def connect(self):
  39. (proxytype, proxyaddr, proxyport, rdns, username, password) = self.proxyargs
  40. rdns = rdns and proxyaddr not in socks4_no_rdns
  41. while True:
  42. try:
  43. sock = socks.create_connection(
  44. (self.host, self.port), self.timeout, None,
  45. proxytype, proxyaddr, proxyport, rdns, username, password,
  46. ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),))
  47. break
  48. except socks.SOCKS4Error as e:
  49. if rdns and "0x5b" in str(e) and not is_ip(self.host):
  50. # Maybe a SOCKS4 server that doesn't support remote resolving
  51. # Let's try again
  52. rdns = False
  53. socks4_no_rdns.add(proxyaddr)
  54. else:
  55. raise
  56. self.sock = sock
  57. class SocksiPyConnectionS(httplib.HTTPSConnection):
  58. def __init__(self, proxytype, proxyaddr, proxyport=None, rdns=True, username=None, password=None, *args, **kwargs):
  59. self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password)
  60. httplib.HTTPSConnection.__init__(self, *args, **kwargs)
  61. def connect(self):
  62. SocksiPyConnection.connect(self)
  63. self.sock = self._context.wrap_socket(self.sock, server_hostname=self.host)
  64. if not self._context.check_hostname and self._check_hostname:
  65. try:
  66. ssl.match_hostname(self.sock.getpeercert(), self.host)
  67. except Exception:
  68. self.sock.shutdown(socket.SHUT_RDWR)
  69. self.sock.close()
  70. raise
  71. class SocksiPyHandler(urllib2.HTTPHandler, urllib2.HTTPSHandler):
  72. def __init__(self, *args, **kwargs):
  73. self.args = args
  74. self.kw = kwargs
  75. urllib2.HTTPHandler.__init__(self)
  76. def http_open(self, req):
  77. def build(host, port=None, timeout=0, **kwargs):
  78. kw = merge_dict(self.kw, kwargs)
  79. conn = SocksiPyConnection(*self.args, host=host, port=port, timeout=timeout, **kw)
  80. return conn
  81. return self.do_open(build, req)
  82. def https_open(self, req):
  83. def build(host, port=None, timeout=0, **kwargs):
  84. kw = merge_dict(self.kw, kwargs)
  85. conn = SocksiPyConnectionS(*self.args, host=host, port=port, timeout=timeout, **kw)
  86. return conn
  87. return self.do_open(build, req)
  88. if __name__ == "__main__":
  89. import sys
  90. try:
  91. port = int(sys.argv[1])
  92. except (ValueError, IndexError):
  93. port = 9050
  94. opener = urllib2.build_opener(SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, "localhost", port))
  95. print("HTTP: " + opener.open("http://httpbin.org/ip").read().decode())
  96. print("HTTPS: " + opener.open("https://httpbin.org/ip").read().decode())