1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
require_relative 'common'
require 'net/ssh/buffer'
require 'net/ssh'
require 'timeout'
require 'tempfile'
require 'net/ssh/proxy/command'
require 'net/ssh/proxy/jump'
class TestProxy < NetSSHTest
include IntegrationTestHelpers
def localhost
'localhost'
end
def user
'net_ssh_1'
end
def ssh_start_params(options)
[localhost,user, { keys: @key_id_rsa }.merge(options)]
end
def setup_ssh_env(&block)
tmpdir do |dir|
@key_id_rsa = "#{dir}/id_rsa"
sh "rm -rf #{@key_id_rsa} #{@key_id_rsa}.pub"
sh "ssh-keygen -q -f #{@key_id_rsa} -t rsa -N ''"
set_authorized_key(user,"#{@key_id_rsa}.pub")
yield
end
end
def setup_gateway(&block)
gwhost = "gateway.netssh"
gwuser = 'net_ssh_2'
tmpdir do |dir|
@gwkey_id_rsa = "#{dir}/id_rsa"
sh "rm -rf #{@gwkey_id_rsa} #{@gwkey_id_rsa}.pub"
sh "ssh-keygen -q -f #{@gwkey_id_rsa} -t rsa -N ''"
set_authorized_key(gwuser,"#{@gwkey_id_rsa}.pub")
config = "Host #{gwhost}
IdentityFile #{@gwkey_id_rsa}
StrictHostKeyChecking no
"
my_config = File.expand_path("~/.ssh/config")
File.open(my_config, 'w') { |file| file.write(config) }
begin
FileUtils.chmod(0o600, my_config)
yield gwuser, gwhost
ensure
FileUtils.rm(my_config)
end
end
end
def test_smoke
setup_ssh_env do
proxy = Net::SSH::Proxy::Command.new("/bin/nc localhost 22")
msg = 'echo123'
ret = Net::SSH.start(*ssh_start_params(proxy: proxy)) do |ssh|
ssh.exec! "echo \"$USER:#{msg}\""
end
assert_equal "net_ssh_1:#{msg}\n", ret
end
end
def with_spurious_write_wakeup_emulate(rate=99,&block)
orig_io_select = IO.method(:select)
count = 0
IO.singleton_class.send(:define_method, :select) do |*params|
count += 1
if (count % rate != 0)
if params && params[1] && !params[1].empty?
return [[],params[1],[]]
end
end
orig_io_select.call(*params)
end
begin
yield
ensure
IO.singleton_class.send(:define_method, :select, &orig_io_select)
end
end
def test_with_rate_limit_and_spurious_wakeup
system("sudo sh -c 'echo 4096 > /proc/sys/fs/pipe-max-size'")
begin
setup_ssh_env do
proxy = Net::SSH::Proxy::Command.new("/usr/bin/pv --rate-limit 100k | /bin/nc localhost 22")
large_msg = 'echo123' * 30000
ok = Net::SSH.start(*ssh_start_params(proxy: proxy)) do |ssh|
with_spurious_write_wakeup_emulate do
ret = ssh.exec! "echo \"$USER:#{large_msg}\""
assert_equal "/bin/sh: Argument list too long\n", ret
hello_count = 1000
ret = ssh.exec! "ruby -e 'puts \"Hello\"*#{hello_count}'"
assert_equal "Hello" * hello_count + "\n", ret
end
:ok
end
assert_equal :ok, ok
end
ensure
system("sudo sh -c 'echo 1048576 > /proc/sys/fs/pipe-max-size'")
end
end
def test_proxy_jump_through_localhost
setup_ssh_env do
setup_gateway do |gwuser, gwhost|
proxy = Net::SSH::Proxy::Jump.new("#{gwuser}@#{gwhost}")
output = Net::SSH.start(*ssh_start_params(proxy: proxy)) do |ssh|
ssh.exec! "echo \"$USER:echo123\""
end
assert_equal "net_ssh_1:echo123\n", output
end
end
end
class DbgProxy
attr_reader :io
def initialize(origin)
@origin = origin
end
def open(*args)
@io = @origin.open(*args)
@io
end
end
def test_does_close_proxy_on_proxy_failure
setup_ssh_env do
proxy = DbgProxy.new(Net::SSH::Proxy::Command.new('sleep 2 && ssh -W %h:%p -o "PreferredAuthentications none" user@localhost'))
msg = 'echo123'
assert_raises Errno::EPIPE, Net::SSH::Proxy::ConnectError do
Net::SSH.start(*ssh_start_params(proxy: proxy, password: 'bad', non_interactive: true, auth_methods: ['password'], verbose: :debug)) do |ssh|
ssh.exec! "echo \"$USER:#{msg}\""
end
end
assert proxy.io.nil? || proxy.io.closed?, "Process #proxy.io.pid not closed"
end
end
end
|