net-ssh 4.0.0.alpha1 → 4.0.0.alpha2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +6 -0
- data/.travis.yml +10 -7
- data/CHANGES.txt +4 -0
- data/Gemfile +2 -15
- data/README.rdoc +6 -37
- data/Rakefile +5 -57
- data/lib/net/ssh/connection/session.rb +13 -0
- data/lib/net/ssh/ruby_compat.rb +2 -24
- data/lib/net/ssh/version.rb +1 -1
- data/net-ssh.gemspec +34 -225
- metadata +26 -100
- metadata.gz.sig +0 -0
- data/test/README.txt +0 -18
- data/test/authentication/methods/common.rb +0 -28
- data/test/authentication/methods/test_abstract.rb +0 -51
- data/test/authentication/methods/test_hostbased.rb +0 -114
- data/test/authentication/methods/test_keyboard_interactive.rb +0 -121
- data/test/authentication/methods/test_none.rb +0 -41
- data/test/authentication/methods/test_password.rb +0 -95
- data/test/authentication/methods/test_publickey.rb +0 -148
- data/test/authentication/test_agent.rb +0 -224
- data/test/authentication/test_ed25519.rb +0 -77
- data/test/authentication/test_key_manager.rb +0 -240
- data/test/authentication/test_session.rb +0 -107
- data/test/common.rb +0 -109
- data/test/configs/auth_off +0 -5
- data/test/configs/auth_on +0 -4
- data/test/configs/empty +0 -0
- data/test/configs/eqsign +0 -3
- data/test/configs/exact_match +0 -8
- data/test/configs/host_plus +0 -10
- data/test/configs/multihost +0 -4
- data/test/configs/negative_match +0 -6
- data/test/configs/nohost +0 -19
- data/test/configs/numeric_host +0 -4
- data/test/configs/proxy_remote_user +0 -2
- data/test/configs/send_env +0 -2
- data/test/configs/substitutes +0 -8
- data/test/configs/wild_cards +0 -14
- data/test/connection/test_channel.rb +0 -487
- data/test/connection/test_session.rb +0 -563
- data/test/integration/README.md +0 -18
- data/test/integration/Vagrantfile +0 -12
- data/test/integration/common.rb +0 -65
- data/test/integration/playbook.yml +0 -57
- data/test/integration/test_ed25519_pkeys.rb +0 -70
- data/test/integration/test_forward.rb +0 -532
- data/test/integration/test_id_rsa_keys.rb +0 -96
- data/test/integration/test_proxy.rb +0 -93
- data/test/known_hosts/github +0 -1
- data/test/known_hosts/github_hash +0 -1
- data/test/manual/test_pageant.rb +0 -37
- data/test/start/test_connection.rb +0 -53
- data/test/start/test_options.rb +0 -57
- data/test/start/test_transport.rb +0 -28
- data/test/start/test_user_nil.rb +0 -27
- data/test/test_all.rb +0 -12
- data/test/test_buffer.rb +0 -433
- data/test/test_buffered_io.rb +0 -63
- data/test/test_config.rb +0 -268
- data/test/test_key_factory.rb +0 -191
- data/test/test_known_hosts.rb +0 -66
- data/test/transport/hmac/test_md5.rb +0 -41
- data/test/transport/hmac/test_md5_96.rb +0 -27
- data/test/transport/hmac/test_none.rb +0 -34
- data/test/transport/hmac/test_ripemd160.rb +0 -36
- data/test/transport/hmac/test_sha1.rb +0 -36
- data/test/transport/hmac/test_sha1_96.rb +0 -27
- data/test/transport/hmac/test_sha2_256.rb +0 -37
- data/test/transport/hmac/test_sha2_256_96.rb +0 -27
- data/test/transport/hmac/test_sha2_512.rb +0 -37
- data/test/transport/hmac/test_sha2_512_96.rb +0 -27
- data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -150
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -96
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -19
- data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
- data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
- data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
- data/test/transport/test_algorithms.rb +0 -328
- data/test/transport/test_cipher_factory.rb +0 -324
- data/test/transport/test_hmac.rb +0 -34
- data/test/transport/test_identity_cipher.rb +0 -40
- data/test/transport/test_packet_stream.rb +0 -1186
- data/test/transport/test_server_version.rb +0 -74
- data/test/transport/test_session.rb +0 -331
- data/test/transport/test_state.rb +0 -181
- data/test/verifiers/test_secure.rb +0 -40
data/test/integration/README.md
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# Integration tests with vagrant
|
2
|
-
|
3
|
-
Requirements:
|
4
|
-
|
5
|
-
* Vagrant (https://www.vagrantup.com/)
|
6
|
-
* Ansible (http://docs.ansible.com/intro_installation.html)
|
7
|
-
|
8
|
-
Setup:
|
9
|
-
|
10
|
-
ansible-galaxy install rvm_io.rvm1-ruby
|
11
|
-
vagrant up ; vagrant ssh
|
12
|
-
rvm all do bundle
|
13
|
-
rvm all do rake test
|
14
|
-
|
15
|
-
# TODO
|
16
|
-
|
17
|
-
* get it running on ci (probalby needs docker)
|
18
|
-
* could not get gem install jeweler to work
|
@@ -1,12 +0,0 @@
|
|
1
|
-
VAGRANTFILE_API_VERSION = "2"
|
2
|
-
|
3
|
-
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
4
|
-
config.vm.box = "ubuntu/trusty64"
|
5
|
-
config.vm.provision "ansible" do |ansible|
|
6
|
-
ansible.playbook = "./playbook.yml"
|
7
|
-
ansible.sudo = true
|
8
|
-
ansible.verbose ='vvvv'
|
9
|
-
end
|
10
|
-
|
11
|
-
config.vm.synced_folder "../..", "/net-ssh"
|
12
|
-
end
|
data/test/integration/common.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../lib"
|
2
|
-
gem "test-unit" # http://rubyforge.org/pipermail/test-unit-tracker/2009-July/000075.html
|
3
|
-
gem 'mocha'
|
4
|
-
require 'test/unit'
|
5
|
-
require 'mocha/setup'
|
6
|
-
require 'pty'
|
7
|
-
require 'expect'
|
8
|
-
|
9
|
-
module IntegrationTestHelpers
|
10
|
-
VERBOSE = false
|
11
|
-
def sh command
|
12
|
-
puts "$ #{command}" if VERBOSE
|
13
|
-
res = system(command)
|
14
|
-
status = $?
|
15
|
-
raise "Command: #{command} failed:#{status.exitstatus}" unless res
|
16
|
-
end
|
17
|
-
|
18
|
-
def tmpdir(&block)
|
19
|
-
Dir.mktmpdir do |dir|
|
20
|
-
yield(dir)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def set_authorized_key(user,pubkey)
|
25
|
-
authorized_key = "/home/#{user}/.ssh/authorized_keys"
|
26
|
-
sh "sudo cp #{pubkey} #{authorized_key}"
|
27
|
-
sh "sudo chown #{user} #{authorized_key}"
|
28
|
-
sh "sudo chmod 0744 #{authorized_key}"
|
29
|
-
end
|
30
|
-
|
31
|
-
def with_agent(&block)
|
32
|
-
puts "/usr/bin/ssh-agent -c" if VERBOSE
|
33
|
-
agent_out = `/usr/bin/ssh-agent -c`
|
34
|
-
agent_out.split("\n").each do |line|
|
35
|
-
if line =~ /setenv (\S+) (\S+);/
|
36
|
-
ENV[$1] = $2
|
37
|
-
puts "ENV[#{$1}]=#{$2}" if VERBOSE
|
38
|
-
end
|
39
|
-
end
|
40
|
-
begin
|
41
|
-
yield
|
42
|
-
ensure
|
43
|
-
sh "/usr/bin/ssh-agent -k > /dev/null"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def ssh_add(key,password)
|
48
|
-
command = "ssh-add #{key}"
|
49
|
-
status = nil
|
50
|
-
PTY.spawn(command) do |reader, writer, pid|
|
51
|
-
begin
|
52
|
-
reader.expect(/Enter passphrase for .*:/) { |data| puts data }
|
53
|
-
writer.puts(password)
|
54
|
-
until reader.eof? do
|
55
|
-
line = reader.readline
|
56
|
-
puts line if VERBOSE
|
57
|
-
end
|
58
|
-
rescue Errno::EIO => _e
|
59
|
-
end
|
60
|
-
pid, status = Process.wait2 pid
|
61
|
-
end
|
62
|
-
raise "Command: #{command} failed:#{status.exitstatus}" unless status
|
63
|
-
status.exitstatus
|
64
|
-
end
|
65
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
---
|
2
|
-
- hosts: all
|
3
|
-
sudo: yes
|
4
|
-
vars:
|
5
|
-
ruby_version: '2.0.0-p598'
|
6
|
-
ruby_versions:
|
7
|
-
- '2.0.0-p598'
|
8
|
-
- '2.3.0'
|
9
|
-
rvm_install_path: '/usr/local/rvm'
|
10
|
-
foopwd: "$6$mhOzf/yapZwS$3RwDl4GfWZ5VcfcsHrK9xNNTxyzLOJBsmMttDNaegIbXxMahV86.v/5HsNtit16MEl0EFf5CSW8Dz2yXV.8GB0"
|
11
|
-
foo2pwd: "$6$JiB7y7.M0yI$Abt.ZGIc4DwkRWeI6nKxzzPUZcux7hLRXSdpoKoZvswJz1SZyg5GRQWn9pGID0dgC6e4wFglfW6ev/qZoTqGk/"
|
12
|
-
pre_tasks:
|
13
|
-
- name: get currently installed ruby version
|
14
|
-
command: "{{rvm_install_path}}/rubies/ruby-{{ruby_version}}/bin/ruby -e 'puts \"#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}\"'"
|
15
|
-
register: current_ruby_version
|
16
|
-
ignore_errors: True
|
17
|
-
roles:
|
18
|
-
- { role: rvm_io.rvm1-ruby,
|
19
|
-
tags: ruby, sudo: True,
|
20
|
-
rvm1_rubies: ["ruby-{{ruby_version}}","ruby-2.3.0"],
|
21
|
-
rvm1_install_path: "{{rvm_install_path}}",
|
22
|
-
rvm1_gpg_key_server: pool.sks-keyservers.net,
|
23
|
-
when: "'{{current_ruby_version.stdout|default()}}' != '{{ruby_version}}'" }
|
24
|
-
tasks:
|
25
|
-
- user: name=net_ssh_1 password="{{foopwd}}" group=vagrant state=present
|
26
|
-
- user: name=net_ssh_2 password="{{foo2pwd}}" group=vagrant state=present
|
27
|
-
- file: dest=/home/net_ssh_1/.ssh/ state=directory mode=0740 owner=net_ssh_1
|
28
|
-
- file: dest=/home/net_ssh_2/.ssh/ state=directory mode=0740 owner=net_ssh_2
|
29
|
-
- lineinfile: dest=/etc/sudoers.d/net_ssh_1 mode=0440 state=present create=yes
|
30
|
-
line='net_ssh_1 ALL=(ALL) NOPASSWD:ALL' regexp=net_ssh_1
|
31
|
-
- lineinfile: dest=/etc/sudoers.d/net_ssh_1 mode=0440 state=present create=yes
|
32
|
-
line='net_ssh_2 ALL=(ALL) NOPASSWD:ALL' regexp=net_ssh_2
|
33
|
-
- command: ssh-keygen -A
|
34
|
-
args:
|
35
|
-
creates: /etc/ssh/ssh_host_ed25519_key
|
36
|
-
notify: restart sshd
|
37
|
-
- name: sshd debug
|
38
|
-
lineinfile: dest='/etc/ssh/sshd_config' line='LogLevel DEBUG' regexp=LogLevel
|
39
|
-
notify: restart sshd
|
40
|
-
- name: put NET_SSH_RUN_INTEGRATION_TESTS=YES environment
|
41
|
-
lineinfile: dest='/etc/environment' line='NET_SSH_RUN_INTEGRATION_TESTS=YES'
|
42
|
-
- name: change dir in bashrc
|
43
|
-
lineinfile: dest=/home/vagrant/.bashrc owner=vagrant mode=0644
|
44
|
-
regexp='^cd ' line='cd /net-ssh'
|
45
|
-
- apt: name="{{item}}" state=present
|
46
|
-
with_items:
|
47
|
-
- pv
|
48
|
-
- libgmp3-dev
|
49
|
-
- gem: name="{{ item[1] }}" state=present user_install=no executable=/usr/local/rvm/wrappers/ruby-{{ item[0] }}/gem
|
50
|
-
with_nested:
|
51
|
-
- "{{ruby_versions}}"
|
52
|
-
- [ 'byebug', 'jeweler', 'mocha', 'rbnacl', 'rbnacl-libsodium' ]
|
53
|
-
- copy: content='echo "cd /net-ssh ; rake integration-test"' dest=/etc/update-motd.d/99-net-ssh-tests mode=0755
|
54
|
-
handlers:
|
55
|
-
- name: restart sshd
|
56
|
-
service: name=ssh state=restarted
|
57
|
-
|
@@ -1,70 +0,0 @@
|
|
1
|
-
require_relative 'common'
|
2
|
-
require 'fileutils'
|
3
|
-
require 'tmpdir'
|
4
|
-
|
5
|
-
require 'net/ssh'
|
6
|
-
|
7
|
-
# see Vagrantfile,playbook for env.
|
8
|
-
# we're running as net_ssh_1 user password foo
|
9
|
-
# and usually connecting to net_ssh_2 user password foo2pwd
|
10
|
-
class TestED25519PKeys < Test::Unit::TestCase
|
11
|
-
include IntegrationTestHelpers
|
12
|
-
|
13
|
-
def test_in_file_no_password
|
14
|
-
Dir.mktmpdir do |dir|
|
15
|
-
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
|
16
|
-
sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N ''"
|
17
|
-
set_authorized_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
|
18
|
-
|
19
|
-
# TODO: fix bug in net ssh which reads public key even if private key is there
|
20
|
-
sh "mv #{dir}/id_rsa_ed25519.pub #{dir}/id_rsa_ed25519.pub.hidden"
|
21
|
-
|
22
|
-
#sshopts = '-vvvv -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
|
23
|
-
#sh "ssh -i #{dir}/id_rsa_ed25519 #{sshopts} net_ssh_1@localhost echo 'hello'"
|
24
|
-
|
25
|
-
ret = Net::SSH.start("localhost", "net_ssh_1", {keys: "#{dir}/id_rsa_ed25519"}) do |ssh|
|
26
|
-
ssh.exec! 'echo "hello from:$USER"'
|
27
|
-
end
|
28
|
-
assert_equal "hello from:net_ssh_1\n", ret
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
def test_ssh_agent
|
34
|
-
Dir.mktmpdir do |dir|
|
35
|
-
with_agent do
|
36
|
-
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
|
37
|
-
sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N 'pwd'"
|
38
|
-
set_authorized_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
|
39
|
-
ssh_add("#{dir}/id_rsa_ed25519","pwd")
|
40
|
-
|
41
|
-
# TODO: fix bug in net ssh which reads public key even if private key is there
|
42
|
-
sh "mv #{dir}/id_rsa_ed25519.pub #{dir}/id_rsa_ed25519.pub.hidden"
|
43
|
-
|
44
|
-
ret = Net::SSH.start("localhost", "net_ssh_1") do |ssh|
|
45
|
-
ssh.exec! 'echo "hello from:$USER"'
|
46
|
-
end
|
47
|
-
assert_equal "hello from:net_ssh_1\n", ret
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_in_file_with_password
|
53
|
-
Dir.mktmpdir do |dir|
|
54
|
-
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
|
55
|
-
sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N 'pwd'"
|
56
|
-
set_authorized_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
|
57
|
-
|
58
|
-
# TODO: fix bug in net ssh which reads public key even if private key is there
|
59
|
-
sh "mv #{dir}/id_rsa_ed25519.pub #{dir}/id_rsa_ed25519.pub.hidden"
|
60
|
-
|
61
|
-
#sshopts = '-vvvv -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
|
62
|
-
#sh "ssh -i #{dir}/id_rsa_ed25519 #{sshopts} net_ssh_1@localhost echo 'hello'"
|
63
|
-
|
64
|
-
ret = Net::SSH.start("localhost", "net_ssh_1", {keys: "#{dir}/id_rsa_ed25519", passphrase:'pwd'}) do |ssh|
|
65
|
-
ssh.exec! 'echo "hello from:$USER"'
|
66
|
-
end
|
67
|
-
assert_equal "hello from:net_ssh_1\n", ret
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,532 +0,0 @@
|
|
1
|
-
# $ ruby -Ilib -Itest -rrubygems test/manual/test_forward.rb
|
2
|
-
|
3
|
-
# Tests for the following patch:
|
4
|
-
#
|
5
|
-
# http://github.com/net-ssh/net-ssh/tree/portfwfix
|
6
|
-
#
|
7
|
-
# It fixes 3 issues, regarding closing forwarded ports:
|
8
|
-
#
|
9
|
-
# 1.) if client closes a forwarded connection, but the server is reading, net-ssh terminates with IOError socket closed.
|
10
|
-
# 2.) if client force closes (RST) a forwarded connection, but server is reading, net-ssh terminates with
|
11
|
-
# 3.) if server closes the sending side, the on_eof is not handled.
|
12
|
-
#
|
13
|
-
# More info:
|
14
|
-
#
|
15
|
-
# http://net-ssh.lighthouseapp.com/projects/36253/tickets/7
|
16
|
-
|
17
|
-
require_relative './common'
|
18
|
-
require 'net/ssh/buffer'
|
19
|
-
require 'net/ssh'
|
20
|
-
require 'timeout'
|
21
|
-
require 'tempfile'
|
22
|
-
|
23
|
-
class TestForward < Test::Unit::TestCase
|
24
|
-
include IntegrationTestHelpers
|
25
|
-
|
26
|
-
def localhost
|
27
|
-
'localhost'
|
28
|
-
end
|
29
|
-
|
30
|
-
def user
|
31
|
-
'net_ssh_1'
|
32
|
-
end
|
33
|
-
|
34
|
-
def ssh_start_params
|
35
|
-
[localhost ,user , {:keys => @key_id_rsa}]
|
36
|
-
end
|
37
|
-
|
38
|
-
def setup_ssh_env(&block)
|
39
|
-
tmpdir do |dir|
|
40
|
-
@key_id_rsa = "#{dir}/id_rsa"
|
41
|
-
sh "rm -rf #{@key_id_rsa} #{@key_id_rsa}.pub"
|
42
|
-
sh "ssh-keygen -q -f #{@key_id_rsa} -t rsa -N ''"
|
43
|
-
set_authorized_key(user,"#{@key_id_rsa}.pub")
|
44
|
-
yield
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def start_server_sending_lot_of_data(exceptions)
|
49
|
-
server = TCPServer.open(0)
|
50
|
-
Thread.start do
|
51
|
-
loop do
|
52
|
-
Thread.start(server.accept) do |client|
|
53
|
-
begin
|
54
|
-
10000.times do |i|
|
55
|
-
client.puts "item#{i}"
|
56
|
-
end
|
57
|
-
client.close
|
58
|
-
rescue
|
59
|
-
exceptions << $!
|
60
|
-
raise
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
return server
|
66
|
-
end
|
67
|
-
|
68
|
-
def start_server_closing_soon(exceptions=nil)
|
69
|
-
server = TCPServer.open(0)
|
70
|
-
Thread.start do
|
71
|
-
loop do
|
72
|
-
Thread.start(server.accept) do |client|
|
73
|
-
begin
|
74
|
-
client.recv(1024)
|
75
|
-
client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii"))
|
76
|
-
client.close
|
77
|
-
rescue
|
78
|
-
exceptions << $!
|
79
|
-
raise
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
return server
|
85
|
-
end
|
86
|
-
|
87
|
-
def test_in_file_no_password
|
88
|
-
setup_ssh_env do
|
89
|
-
ret = Net::SSH.start(*ssh_start_params) do |ssh|
|
90
|
-
#ret = Net::SSH.start("localhost", "net_ssh_1", {keys: @key_id_rsa}) do |ssh|
|
91
|
-
ssh.exec! 'echo "hello from:$USER"'
|
92
|
-
end
|
93
|
-
assert_equal "hello from:net_ssh_1\n", ret
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def test_local_ephemeral_port_should_work_correctly
|
98
|
-
setup_ssh_env do
|
99
|
-
session = Net::SSH.start(*ssh_start_params)
|
100
|
-
|
101
|
-
assert_nothing_raised do
|
102
|
-
assigned_port = session.forward.local(0, localhost, 22)
|
103
|
-
assert_not_nil assigned_port
|
104
|
-
assert_operator assigned_port, :>, 0
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def test_remote_ephemeral_port_should_work_correctly
|
110
|
-
setup_ssh_env do
|
111
|
-
session = Net::SSH.start(*ssh_start_params)
|
112
|
-
|
113
|
-
assert_nothing_raised do
|
114
|
-
session.forward.remote(22, localhost, 0, localhost)
|
115
|
-
session.loop { !(session.forward.active_remotes.length > 0) }
|
116
|
-
assigned_port = session.forward.active_remotes.first[0]
|
117
|
-
assert_not_nil assigned_port
|
118
|
-
assert_operator assigned_port, :>, 0
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def test_remote_callback_should_fire
|
124
|
-
setup_ssh_env do
|
125
|
-
session = Net::SSH.start(*ssh_start_params)
|
126
|
-
|
127
|
-
assert_nothing_raised do
|
128
|
-
got_port = nil
|
129
|
-
session.forward.remote(22, localhost, 0, localhost) do |port|
|
130
|
-
got_port = port
|
131
|
-
end
|
132
|
-
session.loop { !(session.forward.active_remotes.length > 0) }
|
133
|
-
assert_operator session.forward.active_remote_destinations.length, :==, 1
|
134
|
-
assert_operator session.forward.active_remote_destinations.keys.first, :==, [ 22, localhost ]
|
135
|
-
assert_operator session.forward.active_remote_destinations.values.first, :==, [ got_port, localhost ]
|
136
|
-
assert_operator session.forward.active_remotes.first, :==, [ got_port, localhost ]
|
137
|
-
assigned_port = session.forward.active_remotes.first[0]
|
138
|
-
assert_operator got_port, :==, assigned_port
|
139
|
-
assert_not_nil assigned_port
|
140
|
-
assert_operator assigned_port, :>, 0
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def test_remote_callback_should_fire_on_error_and_still_throw_exception
|
146
|
-
setup_ssh_env do
|
147
|
-
session = Net::SSH.start(*ssh_start_params)
|
148
|
-
|
149
|
-
assert_nothing_raised do
|
150
|
-
session.forward.remote(22, localhost, 22, localhost) do |port|
|
151
|
-
assert_operator port, :==, :error
|
152
|
-
end
|
153
|
-
end
|
154
|
-
assert_raises(Net::SSH::Exception) do
|
155
|
-
session.loop { true }
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
def test_remote_callback_should_fire_on_error_but_not_throw_exception_if_asked_not_to
|
161
|
-
setup_ssh_env do
|
162
|
-
session = Net::SSH.start(*ssh_start_params)
|
163
|
-
|
164
|
-
assert_nothing_raised do
|
165
|
-
got_port = nil
|
166
|
-
session.forward.remote(22, localhost, 22, localhost) do |port|
|
167
|
-
assert_operator port, :==, :error
|
168
|
-
got_port = port
|
169
|
-
:no_exception
|
170
|
-
end
|
171
|
-
session.loop { !got_port }
|
172
|
-
assert_operator got_port, :==, :error
|
173
|
-
assert_operator session.forward.active_remotes.length, :==, 0
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def test_loop_should_not_abort_when_local_side_of_forward_is_closed
|
179
|
-
setup_ssh_env do
|
180
|
-
session = Net::SSH.start(*ssh_start_params)
|
181
|
-
server_exc = Queue.new
|
182
|
-
server = start_server_sending_lot_of_data(server_exc)
|
183
|
-
remote_port = server.addr[1]
|
184
|
-
local_port = 0 # request ephemeral port
|
185
|
-
session.forward.local(local_port, localhost, remote_port)
|
186
|
-
client_done = Queue.new
|
187
|
-
Thread.start do
|
188
|
-
begin
|
189
|
-
client = TCPSocket.new(localhost, local_port)
|
190
|
-
client.recv(1024)
|
191
|
-
client.close
|
192
|
-
sleep(0.2)
|
193
|
-
ensure
|
194
|
-
client_done << true
|
195
|
-
end
|
196
|
-
end
|
197
|
-
session.loop(0.1) { client_done.empty? }
|
198
|
-
assert_equal "Broken pipe", "#{server_exc.pop}" unless server_exc.empty?
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
def test_loop_should_not_abort_when_local_side_of_forward_is_reset
|
203
|
-
setup_ssh_env do
|
204
|
-
session = Net::SSH.start(*ssh_start_params)
|
205
|
-
server_exc = Queue.new
|
206
|
-
server = start_server_sending_lot_of_data(server_exc)
|
207
|
-
remote_port = server.addr[1]
|
208
|
-
local_port = 0 # request ephemeral port
|
209
|
-
session.forward.local(local_port, localhost, remote_port)
|
210
|
-
client_done = Queue.new
|
211
|
-
Thread.start do
|
212
|
-
begin
|
213
|
-
client = TCPSocket.new(localhost, local_port)
|
214
|
-
client.recv(1024)
|
215
|
-
client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii"))
|
216
|
-
client.close
|
217
|
-
sleep(0.1)
|
218
|
-
ensure
|
219
|
-
client_done << true
|
220
|
-
end
|
221
|
-
end
|
222
|
-
session.loop(0.1) { client_done.empty? }
|
223
|
-
assert_equal "Broken pipe", "#{server_exc.pop}" unless server_exc.empty?
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def create_local_socket(&blk)
|
228
|
-
tempfile = Tempfile.new("net_ssh_forward_test")
|
229
|
-
path = tempfile.path
|
230
|
-
tempfile.delete
|
231
|
-
yield UNIXServer.open(path)
|
232
|
-
File.delete(path)
|
233
|
-
end if defined?(UNIXServer)
|
234
|
-
|
235
|
-
def test_forward_local_unix_socket_to_remote_port
|
236
|
-
setup_ssh_env do
|
237
|
-
session = Net::SSH.start(*ssh_start_params)
|
238
|
-
server_exc = Queue.new
|
239
|
-
server = start_server_sending_lot_of_data(server_exc)
|
240
|
-
remote_port = server.addr[1]
|
241
|
-
client_data = nil
|
242
|
-
|
243
|
-
create_local_socket do |local_socket|
|
244
|
-
session.forward.local(local_socket, localhost, remote_port)
|
245
|
-
client_done = Queue.new
|
246
|
-
|
247
|
-
Thread.start do
|
248
|
-
begin
|
249
|
-
client = UNIXSocket.new(local_socket.path)
|
250
|
-
client_data = client.recv(1024)
|
251
|
-
client.close
|
252
|
-
sleep(0.2)
|
253
|
-
ensure
|
254
|
-
client_done << true
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
session.loop(0.1) { client_done.empty? }
|
259
|
-
end
|
260
|
-
|
261
|
-
assert_not_nil(client_data, "client should have received data")
|
262
|
-
assert(client_data.match(/item\d/), 'client should have received the string item')
|
263
|
-
end
|
264
|
-
end if defined?(UNIXSocket)
|
265
|
-
|
266
|
-
def test_loop_should_not_abort_when_server_side_of_forward_is_closed
|
267
|
-
setup_ssh_env do
|
268
|
-
session = Net::SSH.start(*ssh_start_params)
|
269
|
-
server = start_server_closing_soon
|
270
|
-
remote_port = server.addr[1]
|
271
|
-
local_port = 0 # request ephemeral port
|
272
|
-
session.forward.local(local_port, localhost, remote_port)
|
273
|
-
client_done = Queue.new
|
274
|
-
Thread.start do
|
275
|
-
begin
|
276
|
-
client = TCPSocket.new(localhost, local_port)
|
277
|
-
1.times do |i|
|
278
|
-
client.puts "item#{i}"
|
279
|
-
end
|
280
|
-
client.close
|
281
|
-
sleep(0.1)
|
282
|
-
ensure
|
283
|
-
client_done << true
|
284
|
-
end
|
285
|
-
end
|
286
|
-
session.loop(0.1) { client_done.empty? }
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
def start_server(server = nil, &block)
|
291
|
-
server ||= TCPServer.open(0)
|
292
|
-
Thread.start do
|
293
|
-
loop do
|
294
|
-
Thread.start(server.accept) do |client|
|
295
|
-
yield(client)
|
296
|
-
end
|
297
|
-
end
|
298
|
-
end
|
299
|
-
return server
|
300
|
-
end
|
301
|
-
|
302
|
-
def test_client_close_should_be_handled_remote
|
303
|
-
setup_ssh_env do
|
304
|
-
message = "This is a small message!"*1000
|
305
|
-
session = Net::SSH.start(*ssh_start_params)
|
306
|
-
server_done = Queue.new
|
307
|
-
server = start_server do |client|
|
308
|
-
begin
|
309
|
-
data = client.read message.size
|
310
|
-
server_done << data
|
311
|
-
client.close
|
312
|
-
rescue
|
313
|
-
server_done << $!
|
314
|
-
end
|
315
|
-
end
|
316
|
-
client_done = Queue.new
|
317
|
-
got_remote_port = Queue.new
|
318
|
-
local_port = server.addr[1]
|
319
|
-
session.forward.remote(0, localhost, local_port) do |actual_remote_port|
|
320
|
-
got_remote_port << actual_remote_port
|
321
|
-
end
|
322
|
-
session.loop(0.1) { got_remote_port.empty? }
|
323
|
-
remote_port = got_remote_port.pop
|
324
|
-
Thread.start do
|
325
|
-
begin
|
326
|
-
client = TCPSocket.new(localhost, remote_port)
|
327
|
-
client.write(message)
|
328
|
-
client.close
|
329
|
-
client_done << true
|
330
|
-
rescue
|
331
|
-
client_done << $!
|
332
|
-
end
|
333
|
-
end
|
334
|
-
Timeout.timeout(5) do
|
335
|
-
session.loop(0.1) { server_done.empty? }
|
336
|
-
assert_equal message, server_done.pop
|
337
|
-
end
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
def test_client_close_should_be_handled
|
342
|
-
setup_ssh_env do
|
343
|
-
message = "This is a small message!"*1000
|
344
|
-
session = Net::SSH.start(*ssh_start_params)
|
345
|
-
server_done = Queue.new
|
346
|
-
server = start_server do |client|
|
347
|
-
begin
|
348
|
-
data = client.read message.size
|
349
|
-
server_done << data
|
350
|
-
client.close
|
351
|
-
rescue
|
352
|
-
server_done << $!
|
353
|
-
end
|
354
|
-
end
|
355
|
-
client_done = Queue.new
|
356
|
-
remote_port = server.addr[1]
|
357
|
-
local_port = session.forward.local(0, localhost, remote_port)
|
358
|
-
Thread.start do
|
359
|
-
begin
|
360
|
-
client = TCPSocket.new(localhost, local_port)
|
361
|
-
client.write(message)
|
362
|
-
client.close
|
363
|
-
client_done << true
|
364
|
-
rescue
|
365
|
-
client_done << $!
|
366
|
-
end
|
367
|
-
end
|
368
|
-
Timeout.timeout(5) do
|
369
|
-
session.loop(0.1) { server_done.empty? }
|
370
|
-
assert_equal message, server_done.pop
|
371
|
-
end
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
def test_server_eof_should_be_handled_remote
|
376
|
-
setup_ssh_env do
|
377
|
-
message = "This is a small message!"
|
378
|
-
session = Net::SSH.start(*ssh_start_params)
|
379
|
-
server = start_server do |client|
|
380
|
-
client.write message
|
381
|
-
client.close
|
382
|
-
end
|
383
|
-
client_done = Queue.new
|
384
|
-
got_remote_port = Queue.new
|
385
|
-
local_port = server.addr[1]
|
386
|
-
session.forward.remote(0, localhost, local_port) do |actual_remote_port|
|
387
|
-
got_remote_port << actual_remote_port
|
388
|
-
end
|
389
|
-
session.loop(0.1) { got_remote_port.empty? }
|
390
|
-
remote_port = got_remote_port.pop
|
391
|
-
Thread.start do
|
392
|
-
begin
|
393
|
-
client = TCPSocket.new(localhost, remote_port)
|
394
|
-
data = client.read(4096)
|
395
|
-
client.close
|
396
|
-
client_done << data
|
397
|
-
rescue
|
398
|
-
client_done << $!
|
399
|
-
end
|
400
|
-
end
|
401
|
-
Timeout.timeout(5) do
|
402
|
-
session.loop(0.1) { client_done.empty? }
|
403
|
-
assert_equal message, client_done.pop
|
404
|
-
end
|
405
|
-
end
|
406
|
-
end
|
407
|
-
|
408
|
-
def test_server_eof_should_be_handled
|
409
|
-
setup_ssh_env do
|
410
|
-
message = "This is a small message!"
|
411
|
-
session = Net::SSH.start(*ssh_start_params)
|
412
|
-
server = start_server do |client|
|
413
|
-
client.write message
|
414
|
-
client.close
|
415
|
-
end
|
416
|
-
client_done = Queue.new
|
417
|
-
remote_port = server.addr[1]
|
418
|
-
local_port = session.forward.local(0, localhost, remote_port)
|
419
|
-
Thread.start do
|
420
|
-
begin
|
421
|
-
client = TCPSocket.new(localhost, local_port)
|
422
|
-
data = client.read(4096)
|
423
|
-
client.close
|
424
|
-
client_done << data
|
425
|
-
rescue
|
426
|
-
client_done << $!
|
427
|
-
end
|
428
|
-
end
|
429
|
-
Timeout.timeout(5) do
|
430
|
-
session.loop(0.1) { client_done.empty? }
|
431
|
-
assert_equal message, client_done.pop
|
432
|
-
end
|
433
|
-
end
|
434
|
-
end
|
435
|
-
|
436
|
-
def _run_reading_client(client_done, local_port)
|
437
|
-
Thread.start do
|
438
|
-
begin
|
439
|
-
client = TCPSocket.new(localhost, local_port)
|
440
|
-
data = client.read(4096)
|
441
|
-
client.close
|
442
|
-
client_done << data
|
443
|
-
rescue
|
444
|
-
client_done << $!
|
445
|
-
end
|
446
|
-
end
|
447
|
-
end
|
448
|
-
|
449
|
-
def test_cannot_open_connection_should_allow_further_connections_on_different_forward
|
450
|
-
setup_ssh_env do
|
451
|
-
session = Net::SSH.start(*ssh_start_params)
|
452
|
-
server = start_server do |client|
|
453
|
-
_data = client.write "hello"
|
454
|
-
client.close
|
455
|
-
end
|
456
|
-
# Forward to a non existing port
|
457
|
-
non_existing_port = 1234
|
458
|
-
local_port = session.forward.local(0, localhost, non_existing_port)
|
459
|
-
# should return connection refused
|
460
|
-
client_done = Queue.new
|
461
|
-
_run_reading_client(client_done, local_port)
|
462
|
-
Timeout.timeout(5) do
|
463
|
-
session.loop(0.1) { client_done.empty? }
|
464
|
-
end
|
465
|
-
assert_equal nil, client_done.pop
|
466
|
-
assert client_done.empty?
|
467
|
-
# Forward to existing port
|
468
|
-
remote_port = server.addr[1]
|
469
|
-
local_port = session.forward.local(0, localhost, remote_port)
|
470
|
-
_run_reading_client(client_done, local_port)
|
471
|
-
Timeout.timeout(5) do
|
472
|
-
session.loop(0.1) { client_done.empty? }
|
473
|
-
end
|
474
|
-
assert_equal "hello", client_done.pop
|
475
|
-
assert client_done.empty?
|
476
|
-
end
|
477
|
-
end
|
478
|
-
|
479
|
-
def test_cannot_open_connection_should_allow_further_connections_on_same
|
480
|
-
setup_ssh_env do
|
481
|
-
session = Net::SSH.start(*ssh_start_params)
|
482
|
-
server = TCPServer.open(0)
|
483
|
-
# Forward to a non existing port
|
484
|
-
remote_port = server.addr[1]
|
485
|
-
server.close
|
486
|
-
local_port = session.forward.local(0, localhost, remote_port)
|
487
|
-
# should return connection refused
|
488
|
-
client_done = Queue.new
|
489
|
-
_run_reading_client(client_done, local_port)
|
490
|
-
Timeout.timeout(5) do
|
491
|
-
session.loop(0.1) { client_done.empty? }
|
492
|
-
end
|
493
|
-
assert_equal nil, client_done.pop
|
494
|
-
assert client_done.empty?
|
495
|
-
# start server
|
496
|
-
server = TCPServer.open(remote_port)
|
497
|
-
server = start_server(server) do |client|
|
498
|
-
_data = client.write "hello"
|
499
|
-
client.close
|
500
|
-
end
|
501
|
-
_run_reading_client(client_done, local_port)
|
502
|
-
Timeout.timeout(5) do
|
503
|
-
session.loop(0.1) { client_done.empty? }
|
504
|
-
end
|
505
|
-
assert_equal "hello", client_done.pop
|
506
|
-
assert client_done.empty?
|
507
|
-
end
|
508
|
-
end
|
509
|
-
|
510
|
-
def test_cancel_local
|
511
|
-
setup_ssh_env do
|
512
|
-
session = Net::SSH.start(*ssh_start_params)
|
513
|
-
server = start_server(server) do |client|
|
514
|
-
_data = client.write "hello"
|
515
|
-
client.close
|
516
|
-
end
|
517
|
-
remote_port = server.addr[1]
|
518
|
-
local_port = session.forward.local(0, localhost, remote_port)
|
519
|
-
# run client
|
520
|
-
client_done = Queue.new
|
521
|
-
_run_reading_client(client_done, local_port)
|
522
|
-
Timeout.timeout(5) do
|
523
|
-
session.loop(0.1) { client_done.empty? }
|
524
|
-
end
|
525
|
-
assert_equal "hello", client_done.pop
|
526
|
-
# cancel
|
527
|
-
session.forward.cancel_local(local_port)
|
528
|
-
session.loop(0.1)
|
529
|
-
assert_equal({}, session.channels)
|
530
|
-
end
|
531
|
-
end
|
532
|
-
end
|