Welcome, guest | Sign In | My Account | Store | Cart

This code shows an implementation of tunneling. Though this code uses ssl as an example. It would not be hard to modify it to work for other situations as well.

The reason I use ssl as an example is because the standard python libraries do not support tunneling ssl through a proxy. Import pytunnel and give it a function w/the code you want to tunnel and your off.

For the latest code try: http://ftp.gnu.org/pub/savannah/cvs/pytunnel-cvs-latest.tar.gz

Python, 132 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import threading,socket,traceback,sys,httplib,pprint,select,base64,time
 
def recv_all(the_socket,timeout=''):
    #setup to use non-blocking sockets
    #assume proxy network connection is worse than locahost
    #if no data arrives it assumes transaction is done
    #recv() returns a string; it's an upper bound on len(sock.recv())
    the_socket.setblocking(0)
    total_data=[];data=''
    begin=time.time()
    if not timeout:
        timeout=1
    while 1:
        #if you got some data, then break after wait sec
        if total_data and time.time()-begin>timeout:
            break
        #if you got no data at all, wait a little longer
        elif time.time()-begin>timeout*2:
            break
        wait=0
        try:
            data=the_socket.recv(4096)
            if data:
                total_data.append(data)
                begin=time.time()
                data='';wait=0
            else:
                time.sleep(0.1)
        except:
            pass
        #When a recv returns 0 bytes, other side has closed
    result=''.join(total_data)
    return result
 
class thread_it ( threading.Thread ) :
    done=0
    def __init__(self,tid='',proxy='',server='',tunnel_client='',\
                 port=0,ip='',timeout=0,slow=0):
        threading.Thread.__init__(self)
        self.tid=tid
        self.proxy=proxy
        self.port=port
        self.server=server
        self.tunnel_client=tunnel_client
        self.ip=ip;self._port=port
        self.data={} #store data here to get later
        self.timeout=timeout
    def run ( self ): #overridden from threading library
        try:
            if self.proxy and self.server:
                ins=[self.server,self.proxy]
                ous=[];data={};adrs={}
                new_socket=0
                while not thread_it.done:
                    if not new_socket:
                        new_socket,address=self.server.accept()
                    else:
                        self.proxy.sendall(
                                  recv_all(new_socket,timeout=self.timeout))
                        new_socket.sendall(
                                  recv_all(self.proxy,timeout=self.timeout))
            elif self.tunnel_client:
                self.tunnel_client(self.ip,self.port)
                thread_it.done=1
        except Exception,error:
            print traceback.print_exc(sys.exc_info()),error
            thread_it.done=1
class build:
    def __init__(self,host='',port=443,proxy_host='',proxy_port=80,
                 proxy_user='',proxy_pass='',proxy_type='',timeout=0):
        #initialize variables
                                                                                
        self._port=port;self.host=host;self._phost=proxy_host;self._puser=proxy_user
        self._pport=proxy_port;self._ppass=proxy_pass;self._ptype=proxy_type
        self.ip='127.0.0.1';self.timeout=timeout
        #setup variables
        self._server,self.server_port=self.get_server()
    def get_proxy(self):
        if not self._ptype:
            proxy=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            proxy.connect((self._phost,self._pport))
            proxy_authorization=''
            if self._puser:
                proxy_authorization='Proxy-authorization: Basic '+\
                base64.encodestring(self._puser+':'+self._ppass).strip()+'\r\n'
            proxy_connect='CONNECT %s:%sHTTP/1.0\r\n'%(self.host,self._port)
            user_agent='User-Agent: pytunnel\r\n'
            proxy_pieces=proxy_connect+proxy_authorization+user_agent+'\r\n'
            proxy.sendall(proxy_pieces+'\r\n')
            response=recv_all(proxy,timeout=0.5)
            status=response.split()[1]
            if int(status)/100 !=2:
                print 'error',response
                raise status
            return proxy
    def get_server(self):
        port=2222
        server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        #localhost = only visible to this machine
        server.bind(('localhost',port))
        server.listen(5)
        return server,port
    def run(self,func):
        Threads=[]
        Threads.append( thread_it(tid=0,proxy=self.get_proxy(),\
                                  server=self._server,timeout=self.timeout))
        Threads.append( thread_it(tid=1,tunnel_client=func,ip=self.ip,\
                                  port=self.server_port,timeout=0.5))
 
        for Thread in Threads: #now go thru list and start threads running
            Thread.start() #call the run function
                print 'error',response
                raise status
            return proxy
    def get_server(self):
        port=2222
        server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        #localhost = only visible to this machine
        server.bind(('localhost',port))
        server.listen(5)
        return server,port
    def run(self,func):
        Threads=[]
        Threads.append( thread_it(tid=0,proxy=self.get_proxy(),\
                                  server=self._server,timeout=self.timeout))
        Threads.append( thread_it(tid=1,tunnel_client=func,ip=self.ip,\
                                  port=self.server_port,timeout=0.5))
 
        for Thread in Threads: #now go thru list and start threads running
            Thread.start() #call the run function
        for Thread in Threads: #make main thread wait for all in list to 
            Thread.join()

import pytunnel,httplib

def tunnel_this(ip,port): conn = httplib.HTTPSConnection(ip,port=port) conn.putrequest('GET', '/') conn.endheaders() response = conn.getresponse() print response.read()

tunnel=pytunnel.build(host='login.yahoo.com',proxy_host='h1', proxy_user='u',proxy_pass='p') tunnel.run(tunnel_this)

Note: Python versions 2.4 and earlier do support non-blocking sockets for ssl I/O. For this example, you may have issues if the proxy server uses non-blocking sockets.

1 comment

Jacek Pliszka 14 years, 10 months ago  # | flag

At the moment it looks outdated:

  1. link given does not work

  2. example code is broken at line 112

Could someone fix it?

Created by John Nielsen on Wed, 30 Jul 2003 (PSF)
Python recipes (4591)
John Nielsen's recipes (36)

Required Modules

  • (none specified)

Other Information and Tasks