Created
May 2, 2012 16:43
-
-
Save gdamjan/2578080 to your computer and use it in GitHub Desktop.
Reverse ssh tunnel - playground
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 python2 | |
import subprocess | |
import random | |
import string | |
import re | |
import sys | |
import tempfile | |
port_re = re.compile(r'^Allocated port (\d+) for remote') | |
def client(server, user, local_port, ssh_port='22'): | |
SSH = 'ssh' | |
if sys.platform == 'win32': | |
SSH = 'plink.exe' | |
cmd = ['ssh', '-T', server, '-l', user, '-p', ssh_port, | |
'-R 0:localhost:%s' % local_port] | |
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
# the ssh daemon sends the client this message, about the port it allocated | |
# on the daemon side. we can't get that info easily in the server script so | |
# just send it over from client side. | |
msg = p.stderr.readline() | |
p.stdin.write(msg) | |
# now we wait for an url allocation | |
url = p.stdout.readline() | |
print url.strip() | |
# and now just wait forever | |
p.wait() | |
def gen_slug(length=6): | |
'''Generate a random combination of letters and digits''' | |
return ''.join(random.sample(string.lowercase + string.digits, length)) | |
# | |
# nginx server config template. takes two parameters the server name | |
# and the port (allocated by sshd) | |
# | |
# the main config will need to have something like: | |
# include /etc/nginx/dynamic-redirects/*.conf; | |
# | |
NGINX_CONF_DIR = '/etc/nginx/dynamic-redirects' | |
NGINX_TEMPLATE ='''\ | |
server { | |
listen [::]:80; | |
listen 80; | |
server_name %(host)s; | |
location / { | |
proxy_pass http://localhost:%(port)s/; | |
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |
proxy_buffering off; | |
proxy_read_timeout 3600; | |
} | |
} | |
''' | |
def server(base_name): | |
# get port from client | |
# configure nginx | |
# send url back | |
msg = sys.stdin.readline() | |
port = port_re.match(msg).group(1) | |
slug = gen_slug() | |
host = slug + '.' + base_name | |
try: | |
fp = tempfile.NamedTemporaryFile(suffix='.conf', dir=NGINX_CONF_DIR) | |
fp.write(NGINX_TEMPLATE % {'host':host, 'port':port}) | |
fp.flush() | |
subprocess.call(['nginx', '-s', 'reload']) | |
sys.stdout.write(host + '\r\n') | |
sys.stdout.flush() | |
# wait forever | |
sys.stdin.read() | |
finaly: | |
del fp | |
# at this point the config file is also deleted | |
subprocess.call(['nginx', '-s', 'reload']) | |
def main(): | |
if sys.argv[1] == '-s': | |
server(sys.argv[2]) | |
else: | |
client(*sys.argv[1:]) | |
if __name__ == '__main__': | |
main() | |
# | |
# A sshd configuration to allow a user with no password | |
# and a forced command (this script). | |
# | |
# the `tunnel` user doesn't have a password | |
# | |
'''\ | |
Match User tunnel | |
ForceCommand /usr/local/bin/reverse-ssh-tunnel.py -s example.com | |
GatewayPorts yes | |
AllowTcpForwarding yes | |
PasswordAuthentication yes | |
PermitEmptyPasswords yes | |
''' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
On the server side I could also use the uWSGI fastrouter. It would simplify the need to sudo reload nginx since uwsgi can reload it's own config files when they are changed.