Parent

Namespace

Class Index [+]

Quicksearch

Net::SSH::Gateway

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.

Constants

MAX_PORT

The maximum port number that the gateway will attempt to use to forward connections from.

MIN_PORT

The minimum port number that the gateway will attempt to use to forward connections from.

Public Class Methods

new(host, user, options={}) click to toggle source

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")

As of 1.1 there is an additional option to specify the wait time for the gateway thread. The default is 0.001 seconds and can be changed with the :loop_wait option.

    # File lib/net/ssh/gateway.rb, line 73
73:   def initialize(host, user, options={})
74:     @session = Net::SSH.start(host, user, options)
75:     @session_mutex = Mutex.new
76:     @port_mutex = Mutex.new
77:     @next_port = MAX_PORT
78:     @loop_wait = options.delete(:loop_wait) || 0.001
79:     initiate_event_loop!
80:   end

Public Instance Methods

active?() click to toggle source

Returns true if the gateway is currently open and accepting connections. This will be the case unless # has been invoked.

    # File lib/net/ssh/gateway.rb, line 84
84:   def active?
85:     @active
86:   end
close(port) click to toggle source

Cancels port-forwarding over an open port that was previously opened via #.

     # File lib/net/ssh/gateway.rb, line 146
146:   def close(port)
147:     ensure_open!
148: 
149:     @session_mutex.synchronize do
150:       @session.forward.cancel_local(port)
151:     end
152:   end
open(host, port, local_port=nil) click to toggle source

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 #) when the block finishes. Otherwise, the port number will be returned, and the caller is responsible for closing the port (#).

  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 121
121:   def open(host, port, local_port=nil)
122:     ensure_open!
123: 
124:     actual_local_port = local_port || next_port
125: 
126:     @session_mutex.synchronize do
127:       @session.forward.local(actual_local_port, host, port)
128:     end
129: 
130:     if block_given?
131:       begin
132:         yield actual_local_port
133:       ensure
134:         close(actual_local_port)
135:       end
136:     else
137:       return actual_local_port
138:     end
139:   rescue Errno::EADDRINUSE
140:     raise if local_port # if a local port was explicitly requested, bubble the error up
141:     retry
142:   end
shutdown!() click to toggle source

Shuts down the gateway by closing all forwarded ports and then closing the gateway’s SSH session.

     # File lib/net/ssh/gateway.rb, line 90
 90:   def shutdown!
 91:     return unless active?
 92: 
 93:     @session_mutex.synchronize do
 94:       # cancel all active forward channels
 95:       @session.forward.active_locals.each do |lport, host, port|
 96:         @session.forward.cancel_local(lport)
 97:       end
 98:     end
 99: 
100:     @active = false
101:     
102:     @thread.join
103:     @session.close
104:   end
ssh(host, user, options={}, &block) click to toggle source

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 170
170:   def ssh(host, user, options={}, &block)
171:     local_port = open(host, options[:port] || 22)
172: 
173:     begin
174:       Net::SSH.start("127.0.0.1", user, options.merge(:port => local_port), &block)
175:     ensure
176:       close(local_port) if block || $!
177:     end
178:   end

Private Instance Methods

ensure_open!() click to toggle source

Raises a RuntimeError if the gateway is not active. This is used as a sanity check to make sure a client doesn’t try to call any methods on a closed gateway.

     # File lib/net/ssh/gateway.rb, line 185
185:     def ensure_open!
186:       raise "attempt to use a closed gateway" unless active?
187:     end
initiate_event_loop!() click to toggle source

Fires up the gateway session’s event loop within a thread, so that it can run in the background. The loop will run for as long as the gateway remains active.

     # File lib/net/ssh/gateway.rb, line 192
192:     def initiate_event_loop!
193:       @active = true
194: 
195:       @thread = Thread.new do
196:         while @active
197:           @session_mutex.synchronize do
198:             @session.process(@loop_wait)
199:           end
200:           Thread.pass
201:         end
202:       end
203:     end
next_port() click to toggle source

Grabs the next available port number and returns it.

     # File lib/net/ssh/gateway.rb, line 206
206:     def next_port
207:       @port_mutex.synchronize do
208:         port = @next_port
209:         @next_port -= 1
210:         @next_port = MAX_PORT if @next_port < MIN_PORT
211:         port
212:       end
213:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.