Class: Net::SSH::Proxy::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/net/ssh/proxy/command.rb

Overview

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command_line_template) ⇒ Command

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.


30
31
32
33
# File 'lib/net/ssh/proxy/command.rb', line 30

def initialize(command_line_template)
  @command_line_template = command_line_template
  @command_line = nil
end

Instance Attribute Details

#command_lineObject (readonly)

The command line for the session


24
25
26
# File 'lib/net/ssh/proxy/command.rb', line 24

def command_line
  @command_line
end

#command_line_templateObject (readonly)

The command line template


21
22
23
# File 'lib/net/ssh/proxy/command.rb', line 21

def command_line_template
  @command_line_template
end

Instance Method Details

#open(host, port, connection_options = nil) ⇒ Object

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


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/net/ssh/proxy/command.rb', line 37

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
    if Gem.win_platform?      # read_nonblock and write_nonblock are not available on Windows
      # pipe. Use sysread and syswrite as a replacement works.

      def send(data, flag)
        syswrite(data)
      end

      def recv(size)
        sysread(size)
      end
    else
      def send(data, flag)
        write_nonblock(data)
      end

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