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