class Net::SSH::Proxy::Command

  1. lib/net/ssh/proxy/command.rb
Parent: Proxy

An implementation of a command proxy. To use it, instantiate it, then pass the instantiated object via the :proxy key to Net::SSH.start:

require 'net/ssh/proxy/command'
proxy = Net::SSH::Proxy::Command.new('ssh relay nc %h %p')
Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
  ...
end

Methods

Public Class

  1. new

Public Instance

  1. command_line
  2. command_line_template
  3. open

Attributes

command_line [R]

The command line for the session

command_line_template [R]

The command line template

Public Class methods

new (command_line_template)

Create a new socket factory that tunnels via a command executed with the user's shell, which is composed from the given command template. In the command template, `%h' will be substituted by the host name to connect and `%p' by the port.

[show source]
# File lib/net/ssh/proxy/command.rb, line 29
def initialize(command_line_template)
  @command_line_template = command_line_template
  @command_line = nil
end

Public Instance methods

open (host, port, connection_options = nil)

Return a new socket connected to the given host and port via the proxy that was requested when the socket factory was instantiated.

[show source]
# File lib/net/ssh/proxy/command.rb, line 36
def open(host, port, connection_options = nil)
  command_line = @command_line_template.gsub(/%(.)/) {
    case $1
    when 'h'
      host
    when 'p'
      port.to_s
    when 'r'
      remote_user = connection_options && connection_options[:remote_user]
      if remote_user
        remote_user
      else
        raise ArgumentError, "remote user name not available"
      end
    when '%'
      '%'
    else
      raise ArgumentError, "unknown key: #{$1}"
    end
  }
  begin
    io = IO.popen(command_line, "r+")
    if result = Net::SSH::Compat.io_select([io], nil, [io], 60)
      if result.last.any?
        raise "command failed"
      end
    else
      raise "command timed out"
    end
  rescue => e
    raise ConnectError, "#{e}: #{command_line}"
  end
  @command_line = command_line
  class << io
    def send(data, flag)
      write_nonblock(data)
    end

    def recv(size)
      read_nonblock(size)
    end
  end
  io
end