forward.py 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #
  2. # This file is adapted from a paramiko demo, and thus licensed under LGPL 2.1.
  3. # Original Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
  4. # Edits Copyright (C) 2010 The IPython Team
  5. #
  6. # Paramiko is free software; you can redistribute it and/or modify it under the
  7. # terms of the GNU Lesser General Public License as published by the Free
  8. # Software Foundation; either version 2.1 of the License, or (at your option)
  9. # any later version.
  10. #
  11. # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
  12. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  13. # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  14. # details.
  15. #
  16. # You should have received a copy of the GNU Lesser General Public License
  17. # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
  18. # 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA.
  19. """
  20. Sample script showing how to do local port forwarding over paramiko.
  21. This script connects to the requested SSH server and sets up local port
  22. forwarding (the openssh -L option) from a local port through a tunneled
  23. connection to a destination reachable from the SSH server machine.
  24. """
  25. from __future__ import print_function
  26. import logging
  27. import select
  28. try: # Python 3
  29. import socketserver
  30. except ImportError: # Python 2
  31. import SocketServer as socketserver
  32. logger = logging.getLogger('ssh')
  33. class ForwardServer (socketserver.ThreadingTCPServer):
  34. daemon_threads = True
  35. allow_reuse_address = True
  36. class Handler (socketserver.BaseRequestHandler):
  37. def handle(self):
  38. try:
  39. chan = self.ssh_transport.open_channel('direct-tcpip',
  40. (self.chain_host, self.chain_port),
  41. self.request.getpeername())
  42. except Exception as e:
  43. logger.debug('Incoming request to %s:%d failed: %s' % (self.chain_host,
  44. self.chain_port,
  45. repr(e)))
  46. return
  47. if chan is None:
  48. logger.debug('Incoming request to %s:%d was rejected by the SSH server.' %
  49. (self.chain_host, self.chain_port))
  50. return
  51. logger.debug('Connected! Tunnel open %r -> %r -> %r' % (self.request.getpeername(),
  52. chan.getpeername(), (self.chain_host, self.chain_port)))
  53. while True:
  54. r, w, x = select.select([self.request, chan], [], [])
  55. if self.request in r:
  56. data = self.request.recv(1024)
  57. if len(data) == 0:
  58. break
  59. chan.send(data)
  60. if chan in r:
  61. data = chan.recv(1024)
  62. if len(data) == 0:
  63. break
  64. self.request.send(data)
  65. chan.close()
  66. self.request.close()
  67. logger.debug('Tunnel closed ')
  68. def forward_tunnel(local_port, remote_host, remote_port, transport):
  69. # this is a little convoluted, but lets me configure things for the Handler
  70. # object. (SocketServer doesn't give Handlers any way to access the outer
  71. # server normally.)
  72. class SubHander (Handler):
  73. chain_host = remote_host
  74. chain_port = remote_port
  75. ssh_transport = transport
  76. ForwardServer(('127.0.0.1', local_port), SubHander).serve_forever()
  77. __all__ = ['forward_tunnel']