Python - Implementing SSH Tunneling Function

Posted by k994519 on Fri, 01 May 2020 11:11:52 +0200

Please indicate the source of the reprint:

Imagine an environment where you can access an SSH server on your intranet and you also want to access a Web server on the same segment.You cannot access the Web server directly, but SSH servers can access the Web server and there are no tools installed on this SSH server that you want to use.
We can use Python to create a forwarded SH tunnel to accomplish these functions, as detailed in the following code:

# -*- coding:UTF-8 -*-
//Files direct data traffic from one port opened by the SSH server to the port of another server specified
//For example, open the command line and enter the following code: -p 8080 -r --user root --password
//After entering the ssh password, the console prints as follows:

----------------------------Console Content Start----------------------------------------
D:\Workspaces\python27\py_hacker\com\lyz\chapter2> -p 8080 -r --user root --password
Enter SSH password:
Connecting to ssh host ...
D:\Program Files\Python27\lib\site-packages\paramiko\ UserWarning: Unknown ssh-rsa host key for 3bc514e5b8ad5377141030149ea79649
  key.get_name(), hostname, hexlify(key.get_fingerprint()),
Now forwarding remote port 8080 to ...

----------------------------Console Content End----------------------------------------

//Indicates that the program has been started successfully. -p 8080 -r --user root --password The purpose is to:
//Data traffic accessing is directed to through the SSH tunnel, that is, opening a browser to access will be directed to through the SSH tunnel.
//In this way, as long as we can access, we cannot directly access In this way, we can also access

Created on 2017 December 19

@author: liuyazhuang

import getpass
import os
import socket
import select
import sys
import threading
from optparse import OptionParser

import paramiko


g_verbose = True

def handler(chan, host, port):
    sock = socket.socket()
        sock.connect((host, port))
    except Exception as e:
        verbose('Forwarding request to %s:%d failed: %r' % (host, port, e))
    verbose('Connected!  Tunnel open %r -> %r -> %r' % (chan.origin_addr,
                                                        chan.getpeername(), (host, port)))
    while True:
        r, w, x =[sock, chan], [], [])
        if sock in r:
            data = sock.recv(1024)
            if len(data) == 0:
        if chan in r:
            data = chan.recv(1024)
            if len(data) == 0:
    verbose('Tunnel closed from %r' % (chan.origin_addr,))

def reverse_forward_tunnel(server_port, remote_host, remote_port, transport):
    transport.request_port_forward('', server_port)
    while True:
        chan = transport.accept(1000)
        if chan is None:
        thr = threading.Thread(target=handler, args=(chan, remote_host, remote_port))

def verbose(s):
    if g_verbose:

HELP = """\
Set up a reverse forwarding tunnel across an SSH server, using paramiko. A
port on the SSH server (given with -p) is forwarded across an SSH session
back to the local machine, and out to a remote site reachable from this
network. This is similar to the openssh -R option.

def get_host_port(spec, default_port):
    "parse 'hostname:22' into a host and port, with the port optional"
    args = (spec.split(':', 1) + [default_port])[:2]
    args[1] = int(args[1])
    return args[0], args[1]

def parse_options():
    global g_verbose
    parser = OptionParser(usage='usage: %prog [options] <ssh-server>[:<server-port>]',
                          version='%prog 1.0', description=HELP)
    parser.add_option('-q', '--quiet', action='store_false', dest='verbose', default=True,
                      help='squelch all informational output')
    parser.add_option('-p', '--remote-port', action='store', type='int', dest='port',
                      help='port on server to forward (default: %d)' % DEFAULT_PORT)
    parser.add_option('-u', '--user', action='store', type='string', dest='user',
                      help='username for SSH authentication (default: %s)' % getpass.getuser())
    parser.add_option('-K', '--key', action='store', type='string', dest='keyfile',
                      help='private key file to use for SSH authentication')
    parser.add_option('', '--no-key', action='store_false', dest='look_for_keys', default=True,
                      help='don\'t look for or use a private key file')
    parser.add_option('-P', '--password', action='store_true', dest='readpass', default=False,
                      help='read password (for key or password auth) from stdin')
    parser.add_option('-r', '--remote', action='store', type='string', dest='remote', default=None, metavar='host:port',
                      help='remote host and port to forward to')
    options, args = parser.parse_args()

    if len(args) != 1:
        parser.error('Incorrect number of arguments.')
    if options.remote is None:
        parser.error('Remote address required (-r).')
    g_verbose = options.verbose
    server_host, server_port = get_host_port(args[0], SSH_PORT)
    remote_host, remote_port = get_host_port(options.remote, SSH_PORT)
    return options, (server_host, server_port), (remote_host, remote_port)

def main():
    options, server, remote = parse_options()
    password = None
    if options.readpass:
        password = getpass.getpass('Enter SSH password: ')
    client = paramiko.SSHClient()

    verbose('Connecting to ssh host %s:%d ...' % (server[0], server[1]))
        client.connect(server[0], server[1], username=options.user, key_filename=options.keyfile,
                       look_for_keys=options.look_for_keys, password=password)
    except Exception as e:
        print('*** Failed to connect to %s:%d: %r' % (server[0], server[1], e))

    verbose('Now forwarding remote port %d to %s:%d ...' % (options.port, remote[0], remote[1]))

        reverse_forward_tunnel(options.port, remote[0], remote[1], client.get_transport())
    except KeyboardInterrupt:
        print('C-c: Port forwarding stopped.')

if __name__ == '__main__':

Topics: ssh Web Server socket Python