Class | Net::SSH::Gateway |
In: |
lib/net/ssh/gateway.rb
|
Parent: | Object |
A Gateway is an object that allows you to tunnel network connections through a publicly visible host to a host hidden behind it. This is particularly useful when dealing with hosts behind a firewall. One host will generally be visible (and accessible) outside the firewall, while the others will all be behind the firewall, and the only way to access those restricted hosts is by first logging into the publicly visible host, and from thence logging into the restricted ones.
This class makes it easy to programmatically connect to these restricted hosts via SSH. You can either simply forward a port from the local host to the remote host, or you can open a new Net::SSH connection to the remote host via a forwarded port.
require 'net/ssh/gateway' gateway = Net::SSH::Gateway.new('host.name', 'user') gateway.open('hidden.host', 80) do |port| Net::HTTP.get_print '127.0.0.1', '/path', port end gateway.ssh('hidden.host', 'user') do |ssh| puts ssh.exec!("hostname") end gateway.shutdown!
Port numbers are allocated automatically, beginning at MAX_PORT and decrementing on each request for a new port until MIN_PORT is reached. If a port is already in use, this is detected and a different port will be assigned.
MAX_PORT | = | 65535 | The maximum port number that the gateway will attempt to use to forward connections from. | |
MIN_PORT | = | 1024 | The minimum port number that the gateway will attempt to use to forward connections from. |
Instantiate a new Gateway object, using the given remote host as the tunnel. The arguments here are identical to those for Net::SSH.start, and are passed as given to that method to start up the gateway connection.
gateway = Net::SSH::Gateway.new('host', 'user', :password => "password")
# File lib/net/ssh/gateway.rb, line 68 68: def initialize(host, user, options={}) 69: @session = Net::SSH.start(host, user, options) 70: @session_mutex = Mutex.new 71: @port_mutex = Mutex.new 72: @next_port = MAX_PORT 73: 74: initiate_event_loop! 75: end
Opens a new port on the local host and forwards it to the given host/port via the gateway host. If a block is given, the newly allocated port number will be yielded to the block, and the port automatically closed (see close) when the block finishes. Otherwise, the port number will be returned, and the caller is responsible for closing the port (close).
gateway.open('host', 80) do |port| # ... end port = gateway.open('host', 80) # ... gateway.close(port)
If local_port is not specified, the next available port will be used.
# File lib/net/ssh/gateway.rb, line 116 116: def open(host, port, local_port=nil) 117: ensure_open! 118: 119: actual_local_port = local_port || next_port 120: 121: @session_mutex.synchronize do 122: @session.forward.local(actual_local_port, host, port) 123: end 124: 125: if block_given? 126: begin 127: yield actual_local_port 128: ensure 129: close(actual_local_port) 130: end 131: else 132: return actual_local_port 133: end 134: rescue Errno::EADDRINUSE 135: raise if local_port # if a local port was explicitly requested, bubble the error up 136: retry 137: end
Shuts down the gateway by closing all forwarded ports and then closing the gateway‘s SSH session.
# File lib/net/ssh/gateway.rb, line 85 85: def shutdown! 86: return unless active? 87: 88: @session_mutex.synchronize do 89: # cancel all active forward channels 90: @session.forward.active_locals.each do |lport, host, port| 91: @session.forward.cancel_local(lport) 92: end 93: end 94: 95: @active = false 96: 97: @thread.join 98: @session.close 99: end
Forwards a new connection to the given host and opens a new Net::SSH connection to that host over the forwarded port. If a block is given, the new SSH connection will be yielded to the block, and autoclosed when the block terminates. The forwarded port will be autoclosed as well. If no block was given, the new SSH connection will be returned, and it is up to the caller to terminate both the connection and the forwarded port when done.
gateway.ssh('host', 'user') do |ssh| # ... end ssh = gateway.ssh('host', 'user') # ... ssh.close gateway.close(ssh.transport.port)
# File lib/net/ssh/gateway.rb, line 165 165: def ssh(host, user, options={}, &block) 166: local_port = open(host, options[:port] || 22) 167: 168: begin 169: Net::SSH.start("127.0.0.1", user, options.merge(:port => local_port), &block) 170: ensure 171: close(local_port) if block || $! 172: end 173: end