Skip to content

Instantly share code, notes, and snippets.

@jmendeth jmendeth/README.md
Last active Jun 10, 2019

Embed
What would you like to do?
Wrapper that simplifies SSH tunnels

ssh-from

ssh-from simplifies common usage of SSH tunnels, and makes double (or triple) tunnels a piece of cake.
Here is an example, where I SSH to a computer that is behind two NATs, tunneling through each router:

Double tunnel example

Details coming to the blog soon.

Installation

Install dependencies (tsocks is optional):

sudo apt-get install python3 lsof tsocks

Then download the script somewhere in your PATH and make it executable:

sudo wget https://gist.github.com/jmendeth/346f2233310d8292efe7595d60aa3659/raw/ssh-from.py -O /usr/local/bin/ssh-from
sudo chmod a+rx /usr/local/bin/ssh-from

I highly recommend you install this helper program as well.

#!/usr/bin/env python3
# Dependencies: lsof
import sys, os, signal, subprocess, socket, random, atexit, tempfile
addr = "127.0.0.1"
ssh_args = sys.argv[1:]
# Find free port
tsock = socket.socket()
while True:
port = random.randint(8192, 65535)
try:
tsock.bind((addr, port))
break
except socket.error:
pass
# Start SSH proxy
tsock.close()
ssh = subprocess.Popen(["ssh", "-fND", "%s:%d" % (addr, port)] + ssh_args)
while True:
try:
r = ssh.wait()
break
except KeyboardInterrupt:
ssh.send_signal(signal.SIGINT)
if r != 0: exit(r)
print("\nConnected ({}).".format(" ".join(ssh_args)))
# Modify env
proxy = "socks5://%s:%d" % (addr, port)
for var in ["http_proxy", "https_proxy", "ftp_proxy", "rsync_proxy", "ssh_proxy", "all_proxy"]:
os.putenv(var, proxy)
os.putenv(var.upper(), proxy)
os.putenv("no_proxy", "")
os.putenv("ssh_from_orig", " ".join(ssh_args))
# Create tsocks config file, just in case
tsconf = tempfile.NamedTemporaryFile(suffix=".conf", delete=False)
tsconf.write("server = {}\nserver_port = {}\nserver_type = 5\n".format(addr, port).encode('ascii'))
tsconf.close()
os.putenv("TSOCKS_CONF_FILE", tsconf.name)
# Terminate ssh proxy at exit
def cleanup():
out = subprocess.check_output(["lsof", "-iTCP@%s:%d" % (addr, port), "-sTCP:LISTEN", "-Fp"])
pid = int({ o[0]: o[1:] for o in out.decode('ascii').splitlines() }["p"])
os.kill(pid, signal.SIGTERM)
orig = os.getenv("ssh_from_orig")
if orig: print("Back at ({}).".format(orig))
else: print("All SSH proxies terminated.")
os.remove(tsconf.name)
atexit.register(cleanup)
# Run shell
sh = subprocess.Popen([os.environ["SHELL"] or "sh"])
while True:
try:
exit(sh.wait())
except KeyboardInterrupt:
sh.send_signal(signal.SIGINT)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.