I often connect to Internet from a connection which blocks, by default, outgoing connections except for some given ports.
For instance, port 80 (http) is open, as are 443 (https), 995 (pop3s) and a few others… but port 22 (ssh) is closed. So if I want to be able to connect via ssh to a server of mine, I must configure the server to listen (also) on a different port… non blocked. Configuring the server to listen on multiple ports is trivial, this page is devoted to the problem of understanding which port can be used.
My rudimentary solution is composed of 4 simple Python scripts:
Notice that you don't need scripts 2. and 3. if you have a way to connect to the remote host 1).
Click here to download all 4 scripts in this page at once - they are released as GPL v.3+.
The script just runs a dummy service on each port from N (provided as argument) to N+257 (I don't check more than 257 ports at the same time, to not incur in the restrictions imposed on the maximum number of opened files).
As suggested in the comment, you should replace “socket.gethostname()” with the hostname the server is accessible to, i.e.
s.bind( ("example.com", port) )
because socket.gethostname() probably won't work.
#! /usr/bin/python # opener.py import socket, time, sys try: start = int( sys.argv[1] ) except (IndexError, ValueError): print "usage: %s first_port" % sys.argv[0] sys.exit(1) sockets = [] for port in range(start, start + 257): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: # You should probably edit the following line! s.bind( (socket.gethostname(), port) ) s.listen(1) except Exception as exc: print port, exc sockets.append( s ) time.sleep(3600)
Put this in some place where Python files will be executed by the webserver (i.e. /usr/lib/cgi-bin/ , but depends on the configuration). Notice Apache doesn't execute Python files out of the box: mod_python must be installed and maybe configured.
#! /usr/bin/python # http_control.py import cgi import cgitb cgitb.enable() print "Content-type: text/html\n" form_c = cgi.FormContentDict() if 'p' in form_c: f = open( 'port', 'w') f.write( form_c['p'][0] ) print form_c f.close()
The above script creates a file, in the same folder, called “port”. This one looks at that script and runs “ports_opener.py” accordingly. So you must replace '/path/to/port/file' with the full path of the “port” file, and save it in the same folder as “opener.py”.
#! /usr/bin/python # bridge.py import time, subprocess port = None proc = None while True: newf = open('/path/to/port/file') try: newport = int( newf.read() ) except ValueError: newport = None newf.close() if newport != port: if proc: proc.terminate() if newport != None: print "starting", ["./opener.py", str( newport )] proc = subprocess.Popen(["./opener.py", str( newport )]) else: print "stopped" port = newport time.sleep( 5 )
This is a very simple port scanner: it tries to connect to a given range of ports on the given host (again, from N, the argument, to N+257). You must replace “put.here.the.hostname” with the true address of your server (the same you presumably replaced “socket.gethostname()” with above).
#! /usr/bin/python # prober.py import socket, time, sys try: start = int( sys.argv[1] ) except (IndexError, ValueError): print "usage: %s first_port" % sys.argv[0] sys.exit(1) if len(sys.argv) > 2: host = sys.argv[2] else: # Edit the following line! host = "put.here.the.hostname" sockets = [] for port in range(start, start + 257): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) res = s.connect_ex( (host, port) ) if res == 0: print "PORT ", port, " OPEN" else: print port, res
If you have an alternate access to the server, just run on it “opener.py”, like in
./opener.py 100
and on the client run “prober.py” with the same argument
./prober.py 100
to test ports 100 - 357 (and try again with some other argument to test other ports ranges).
If you don't have an alternate access to the server, from another connection, some time before
Then, once you are behind the firewalled connection, assuming that http_control.py can be accessed at http://www.example.com/http_control.py, just
./prober.py 100
to test ports 100 - 357 (and try again with some other argument to test other ports ranges).
prober.py will print “OPEN” for every port it finds open. You will know those ports are not filtered. Still, notice that some of them will already be in use by existing services of your server: you must find some free one in order to run ssh at it. Just compare the output of prober.py with what you obtain when running ./prober.py against you host with opener.py not in action (if you use http_control.py, you can disable it by visiting “http://www.example.com/http_control.py?p=None”). Ports which result open in the first case but not in the second are what you're searching for.