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

Pinhole is a simple network utility that forwards a port to the host specified. The optional newport parameter may be used to redirect to a different port on the target host. Uses threads gratuitously.

Python, 85 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
"""
usage 'pinhole port host [newport]'

Pinhole forwards the port to the host specified.
The optional newport parameter may be used to
redirect to a different port.

eg. pinhole 80 webserver
    Forward all incoming WWW sessions to webserver.

    pinhole 23 localhost 2323
    Forward all telnet sessions to port 2323 on localhost.
"""

import sys
from socket import *
from threading import Thread
import time

LOGGING = 1

def log( s ):
    if LOGGING:
        print '%s:%s' % ( time.ctime(), s )
        sys.stdout.flush()

class PipeThread( Thread ):
    pipes = []
    def __init__( self, source, sink ):
        Thread.__init__( self )
        self.source = source
        self.sink = sink

        log( 'Creating new pipe thread  %s ( %s -> %s )' % \
            ( self, source.getpeername(), sink.getpeername() ))
        PipeThread.pipes.append( self )
        log( '%s pipes active' % len( PipeThread.pipes ))

    def run( self ):
        while 1:
            try:
                data = self.source.recv( 1024 )
                if not data: break
                self.sink.send( data )
            except:
                break

        log( '%s terminating' % self )
        PipeThread.pipes.remove( self )
        log( '%s pipes active' % len( PipeThread.pipes ))
        
class Pinhole( Thread ):
    def __init__( self, port, newhost, newport ):
        Thread.__init__( self )
        log( 'Redirecting: localhost:%s -> %s:%s' % ( port, newhost, newport ))
        self.newhost = newhost
        self.newport = newport
        self.sock = socket( AF_INET, SOCK_STREAM )
        self.sock.bind(( '', port ))
        self.sock.listen(5)
    
    def run( self ):
        while 1:
            newsock, address = self.sock.accept()
            log( 'Creating new session for %s %s ' % address )
            fwd = socket( AF_INET, SOCK_STREAM )
            fwd.connect(( self.newhost, self.newport ))
            PipeThread( newsock, fwd ).start()
            PipeThread( fwd, newsock ).start()
       
if __name__ == '__main__':

    print 'Starting Pinhole'

    import sys
    sys.stdout = open( 'pinhole.log', 'w' )
    
    if len( sys.argv ) > 1:
        port = newport = int( sys.argv[1] )
        newhost = sys.argv[2]
        if len( sys.argv ) == 4: newport = int( sys.argv[3] )
        Pinhole( port, newhost, newport ).start()
    else:
        Pinhole( 80, 'hydrogen', 80 ).start()
        Pinhole( 23, 'hydrogen', 23 ).start()

3 comments

Johan Geldenhuys 19 years, 7 months ago  # | flag

Pinhole. I want to know more on how you use the Thread class to get two sockets to talk to eachother. I want to set a socket server and then forward all incoming data to a client connection (This server and client is in the same script) that connects to another socket server on a different machine. Thanks Your code looks simple enough so that I can use the idea.

Johan

realfun 13 years, 7 months ago  # | flag

This is exactly what I want, works like a charm, thanks a lot.

leolee192 8 years, 1 month ago  # | flag

We found the connection between client and proxy won't be closed automatically. The discussions and refines are at http://stackoverflow.com/questions/35476691/why-do-i-need-ctrl-c-when-curl-to-the-this-tcp-proxy/