Please indicate the source of the reprint: http://blog.csdn.net/l1028386804/article/details/78845722
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: rforward.py 192.168.209.121 -p 8080 -r 192.168.209.122:80 --user root --password //After entering the ssh password, the console prints as follows: ----------------------------Console Content Start---------------------------------------- D:\Workspaces\python27\py_hacker\com\lyz\chapter2>rforward.py 192.168.209.121 -p 8080 -r 192.168.209.122:80 --user root --password Enter SSH password: Connecting to ssh host 192.168.209.121 ... D:\Program Files\Python27\lib\site-packages\paramiko\client.py:779: UserWarning: Unknown ssh-rsa host key for 192.168.209.121: 3bc514e5b8ad5377141030149ea79649 key.get_name(), hostname, hexlify(key.get_fingerprint()), Now forwarding remote port 8080 to 192.168.209.122:80 ... ----------------------------Console Content End---------------------------------------- //Indicates that the program has been started successfully. rforward.py 192.168.209.121 -p 8080 -r 192.168.209.122:80 --user root --password The purpose is to: //Data traffic accessing 192.168.209.121:8080 is directed to 192.168.209.122:80 through the SSH tunnel, that is, opening a browser to access http://192.168.209.121:8080 will be directed to http://192.168.209.122:80 through the SSH tunnel. //In this way, as long as we can access http://192.168.209.121:8080, we cannot directly access http://192.168.209.122:80. In this way, we can also access http://192.168.209.122:80. 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 SSH_PORT = 22 DEFAULT_PORT = 4000 g_verbose = True def handler(chan, host, port): sock = socket.socket() try: sock.connect((host, port)) except Exception as e: verbose('Forwarding request to %s:%d failed: %r' % (host, port, e)) return verbose('Connected! Tunnel open %r -> %r -> %r' % (chan.origin_addr, chan.getpeername(), (host, port))) while True: r, w, x = select.select([sock, chan], [], []) if sock in r: data = sock.recv(1024) if len(data) == 0: break chan.send(data) if chan in r: data = chan.recv(1024) if len(data) == 0: break sock.send(data) chan.close() sock.close() 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: continue thr = threading.Thread(target=handler, args=(chan, remote_host, remote_port)) thr.setDaemon(True) thr.start() def verbose(s): if g_verbose: print(s) 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', default=DEFAULT_PORT, help='port on server to forward (default: %d)' % DEFAULT_PORT) parser.add_option('-u', '--user', action='store', type='string', dest='user', default=getpass.getuser(), help='username for SSH authentication (default: %s)' % getpass.getuser()) parser.add_option('-K', '--key', action='store', type='string', dest='keyfile', default=None, 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() client.load_system_host_keys() client.set_missing_host_key_policy(paramiko.WarningPolicy()) verbose('Connecting to ssh host %s:%d ...' % (server[0], server[1])) try: 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)) sys.exit(1) verbose('Now forwarding remote port %d to %s:%d ...' % (options.port, remote[0], remote[1])) try: reverse_forward_tunnel(options.port, remote[0], remote[1], client.get_transport()) except KeyboardInterrupt: print('C-c: Port forwarding stopped.') sys.exit(0) if __name__ == '__main__': main()