-
-
Save xiocode/2840381 to your computer and use it in GitHub Desktop.
A simple port multiplexer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
# | |
# author: mayli <[email protected]> | |
# | |
# Modified from Pinhole, and the original code is found here: | |
# {{{ http://code.activestate.com/recipes/114642/ (r1) | |
# | |
""" | |
usage: pinhole | |
This program forwards a local port to different ports by guessing the protocol, | |
also can be called port-multiplex. It's useful when you behind a NAT and only | |
have one port availabe. | |
Changing the guessing part can achieve more services multiplex, but you have | |
to find some "pattern" between these services' protocol. | |
Configure HOSTS to match your server. | |
Test your configuration by, and see it works: | |
POP3S:openssl s_client -connect 127.0.0.1:9955 -showcerts | |
SSH:ssh 192.168.0.101 -p 9955 | |
NOTE:To listen on port below 1024 on linux needs ROOT privilage. | |
""" | |
import sys | |
from socket import * | |
from threading import Thread | |
import time | |
import select | |
# Configure HOSTS to match your server | |
HOSTS = { | |
'ExtIP':('192.168.0.101',9955), | |
'POP3S':('pop.gmail.com',995), # Might be 127.0.0.1:995 in your case | |
'SSH':('127.0.0.1',22), | |
} | |
LOGGING = 1 | |
CLIENT_TIMEOUT = 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 ): | |
Thread.__init__( self ) | |
self.port=port | |
self.sock = socket( AF_INET, SOCK_STREAM ) | |
self.sock.bind(HOSTS['ExtIP']) | |
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 ) | |
# Guess which protocol is used. | |
# Normally the ssh client will keep slient until server say 'SSH', | |
# but pop3s needs client to send header to ssl shake. | |
# So, we wait 1 s | |
ready=select.select([newsock],[],[],CLIENT_TIMEOUT) | |
if ready[0]: | |
print 'POP3 ready' | |
fwd.connect(HOSTS['POP3S']) | |
else: | |
print 'SSH ready' | |
# The ssh case | |
fwd.connect(HOSTS['SSH']) | |
log( 'Redirecting: localhost:%s -> %s' % ( self.port, repr(fwd.getpeername()) )) | |
PipeThread( newsock, fwd ).start() | |
PipeThread( fwd, newsock ).start() | |
if __name__ == '__main__': | |
print 'Starting Pinhole' | |
#import sys | |
#sys.stdout = open( 'pinhole.log', 'w' ) | |
Pinhole( HOSTS['ExtIP'][1] ).start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment