net-ssh 2.9.1 → 2.9.2.beta
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 +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/CHANGES.txt +5 -0
- data/README.rdoc +5 -0
- data/Rakefile +9 -3
- data/lib/net/ssh.rb +2 -1
- data/lib/net/ssh/authentication/agent/socket.rb +10 -4
- data/lib/net/ssh/authentication/methods/password.rb +35 -10
- data/lib/net/ssh/buffer.rb +1 -1
- data/lib/net/ssh/config.rb +4 -2
- data/lib/net/ssh/connection/keepalive.rb +48 -0
- data/lib/net/ssh/connection/session.rb +4 -25
- data/lib/net/ssh/errors.rb +4 -0
- data/lib/net/ssh/known_hosts.rb +2 -10
- data/lib/net/ssh/service/forward.rb +52 -12
- data/lib/net/ssh/transport/algorithms.rb +10 -9
- data/lib/net/ssh/transport/cipher_factory.rb +0 -3
- data/lib/net/ssh/transport/packet_stream.rb +3 -1
- data/lib/net/ssh/transport/session.rb +7 -2
- data/lib/net/ssh/version.rb +11 -7
- data/net-ssh-public_cert.pem +20 -0
- data/net-ssh.gemspec +11 -9
- data/test/authentication/methods/test_password.rb +43 -0
- data/test/authentication/test_agent.rb +19 -0
- data/test/connection/test_session.rb +19 -2
- data/test/manual/test_forward.rb +76 -27
- data/test/test_config.rb +3 -1
- data/test/transport/test_algorithms.rb +40 -45
- data/test/transport/test_packet_stream.rb +7 -1
- data/test/transport/test_session.rb +12 -0
- metadata +39 -51
- metadata.gz.sig +0 -0
- data/gem-public_cert.pem +0 -20
@@ -42,14 +42,12 @@ module Net; module SSH; module Transport
|
|
42
42
|
camellia192-ctr@openssh.org
|
43
43
|
camellia256-ctr@openssh.org
|
44
44
|
cast128-ctr blowfish-ctr 3des-ctr
|
45
|
-
aes256-gcm@openssh.com aes128-gcm@openssh.com
|
46
45
|
),
|
46
|
+
|
47
47
|
:hmac => %w(hmac-sha1 hmac-md5 hmac-sha1-96 hmac-md5-96
|
48
48
|
hmac-ripemd160 hmac-ripemd160@openssh.com
|
49
49
|
hmac-sha2-256 hmac-sha2-512 hmac-sha2-256-96
|
50
|
-
hmac-sha2-512-96 none
|
51
|
-
hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com
|
52
|
-
umac-128-etm@openssh.com),
|
50
|
+
hmac-sha2-512-96 none),
|
53
51
|
|
54
52
|
:compression => %w(none zlib@openssh.com zlib),
|
55
53
|
:language => %w()
|
@@ -57,9 +55,7 @@ module Net; module SSH; module Transport
|
|
57
55
|
if defined?(OpenSSL::PKey::EC)
|
58
56
|
ALGORITHMS[:host_key] += %w(ecdsa-sha2-nistp256
|
59
57
|
ecdsa-sha2-nistp384
|
60
|
-
ecdsa-sha2-nistp521
|
61
|
-
ssh-ed25519-cert-v01@openssh.com
|
62
|
-
ssh-ed25519)
|
58
|
+
ecdsa-sha2-nistp521)
|
63
59
|
ALGORITHMS[:kex] += %w(ecdh-sha2-nistp256
|
64
60
|
ecdh-sha2-nistp384
|
65
61
|
ecdh-sha2-nistp521
|
@@ -221,8 +217,13 @@ module Net; module SSH; module Transport
|
|
221
217
|
# apply the preferred algorithm order, if any
|
222
218
|
if options[algorithm]
|
223
219
|
algorithms[algorithm] = Array(options[algorithm]).compact.uniq
|
224
|
-
|
225
|
-
|
220
|
+
unsupported = []
|
221
|
+
algorithms[algorithm].select! do |name|
|
222
|
+
supported = ALGORITHMS[algorithm].include?(name)
|
223
|
+
unsupported << name unless supported
|
224
|
+
supported
|
225
|
+
end
|
226
|
+
lwarn { "unsupported #{algorithm} algorithm: `#{unsupported}'" } unless unsupported.empty?
|
226
227
|
|
227
228
|
# make sure all of our supported algorithms are tacked onto the
|
228
229
|
# end, so that if the user tries to give a list of which none are
|
@@ -41,9 +41,6 @@ module Net; module SSH; module Transport
|
|
41
41
|
"camellia192-ctr@openssh.org" => "camellia-192-ecb",
|
42
42
|
"camellia256-ctr@openssh.org" => "camellia-256-ecb",
|
43
43
|
|
44
|
-
"aes256-gcm@openssh.com" => "aes-256-gcm",
|
45
|
-
"aes128-gcm@openssh.com" => "aes-128-gcm",
|
46
|
-
|
47
44
|
"none" => "none",
|
48
45
|
}
|
49
46
|
|
@@ -14,6 +14,8 @@ module Net; module SSH; module Transport
|
|
14
14
|
# per the SSH2 protocol. It also adds an abstraction for polling packets,
|
15
15
|
# to allow for both blocking and non-blocking reads.
|
16
16
|
module PacketStream
|
17
|
+
PROXY_COMMAND_HOST_IP = '<no hostip for proxy command>'.freeze
|
18
|
+
|
17
19
|
include BufferedIo
|
18
20
|
|
19
21
|
def self.extended(object)
|
@@ -64,7 +66,7 @@ module Net; module SSH; module Transport
|
|
64
66
|
addr = getpeername
|
65
67
|
Socket.getnameinfo(addr, Socket::NI_NUMERICHOST | Socket::NI_NUMERICSERV).first
|
66
68
|
else
|
67
|
-
|
69
|
+
PROXY_COMMAND_HOST_IP
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
@@ -93,11 +93,16 @@ module Net; module SSH; module Transport
|
|
93
93
|
@host_as_string ||= begin
|
94
94
|
string = "#{host}"
|
95
95
|
string = "[#{string}]:#{port}" if port != DEFAULT_PORT
|
96
|
-
|
97
|
-
|
96
|
+
|
97
|
+
peer_ip = socket.peer_ip
|
98
|
+
|
99
|
+
if peer_ip != Net::SSH::Transport::PacketStream::PROXY_COMMAND_HOST_IP &&
|
100
|
+
peer_ip != host
|
101
|
+
string2 = peer_ip
|
98
102
|
string2 = "[#{string2}]:#{port}" if port != DEFAULT_PORT
|
99
103
|
string << "," << string2
|
100
104
|
end
|
105
|
+
|
101
106
|
string
|
102
107
|
end
|
103
108
|
end
|
data/lib/net/ssh/version.rb
CHANGED
@@ -16,15 +16,15 @@ module Net; module SSH
|
|
16
16
|
|
17
17
|
# A convenience method for instantiating a new Version instance with the
|
18
18
|
# given +major+, +minor+, and +tiny+ components.
|
19
|
-
def self.[](major, minor, tiny)
|
20
|
-
new(major, minor, tiny)
|
19
|
+
def self.[](major, minor, tiny, pre = nil)
|
20
|
+
new(major, minor, tiny, pre)
|
21
21
|
end
|
22
22
|
|
23
23
|
attr_reader :major, :minor, :tiny
|
24
24
|
|
25
25
|
# Create a new Version object with the given components.
|
26
|
-
def initialize(major, minor, tiny)
|
27
|
-
@major, @minor, @tiny = major, minor, tiny
|
26
|
+
def initialize(major, minor, tiny, pre = nil)
|
27
|
+
@major, @minor, @tiny, @pre = major, minor, tiny, pre
|
28
28
|
end
|
29
29
|
|
30
30
|
# Compare this version to the given +version+ object.
|
@@ -35,7 +35,7 @@ module Net; module SSH
|
|
35
35
|
# Converts this version object to a string, where each of the three
|
36
36
|
# version components are joined by the '.' character. E.g., 2.0.0.
|
37
37
|
def to_s
|
38
|
-
@to_s ||= [@major, @minor, @tiny].join(".")
|
38
|
+
@to_s ||= [@major, @minor, @tiny, @pre].compact.join(".")
|
39
39
|
end
|
40
40
|
|
41
41
|
# Converts this version to a canonical integer that may be compared
|
@@ -51,10 +51,14 @@ module Net; module SSH
|
|
51
51
|
MINOR = 9
|
52
52
|
|
53
53
|
# The tiny component of this version of the Net::SSH library
|
54
|
-
TINY =
|
54
|
+
TINY = 2
|
55
|
+
|
56
|
+
# The prerelease component of this version of the Net::SSH library
|
57
|
+
# nil allowed
|
58
|
+
PRE = "beta"
|
55
59
|
|
56
60
|
# The current version of the Net::SSH library as a Version instance
|
57
|
-
CURRENT = new(MAJOR, MINOR, TINY)
|
61
|
+
CURRENT = new(*[MAJOR, MINOR, TINY, PRE].compact)
|
58
62
|
|
59
63
|
# The current version of the Net::SSH library as a String
|
60
64
|
STRING = CURRENT.to_s
|
@@ -0,0 +1,20 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRAwDgYDVQQDDAduZXQt
|
3
|
+
c3NoMRkwFwYKCZImiZPyLGQBGRYJc29sdXRpb3VzMRMwEQYKCZImiZPyLGQBGRYD
|
4
|
+
Y29tMB4XDTE0MTIwMjE3MzkyMFoXDTE1MTIwMjE3MzkyMFowQjEQMA4GA1UEAwwH
|
5
|
+
bmV0LXNzaDEZMBcGCgmSJomT8ixkARkWCXNvbHV0aW91czETMBEGCgmSJomT8ixk
|
6
|
+
ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0qnw4JV5JN
|
7
|
+
MWelqu7pnW2z6GZJ7+zLFYJQNETJyF0U5zo7aCRK08OeUxnpu/TCCXK8iQVkNLfz
|
8
|
+
9pVIhF+X8pMEIruAkYGwBt1aWfuSNeyodyMk0vpZdxBHbOTJ4qBRUc6qOtNOeOzv
|
9
|
+
8ObYUX52P/EMMaeXTRU+e7MGkB9pb6FvPPNx5akxwIaoRvtcMsc/hJnQuP5r96w6
|
10
|
+
t06MgKbXhWAX6gev0RVlrQqzxXst6iuvsrgZGjFqzob5wbTiX9M0+bFAB0EI7tJC
|
11
|
+
sv5keEbtNRaU7p3ZbMm4wTHHJLOtD+BpUCSzwv4ToNj9mZtJBMYw2Eeo7z1DklEG
|
12
|
+
mr95zbe+zNMCAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQU1bTfpzmitXwv
|
13
|
+
LmTXi0IO5vd8NGYwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQA0Aps8
|
14
|
+
UPINGa8XUUtrZtzrgX0/iyXNkKY1ld85g1N3WKEAVLfQI7TlGr0Qv2Ekx6RqlxbR
|
15
|
+
Vyq08pytSnghW2otR3bIGMGQzqxAeRLb25cjEwH7YIJ32n7ZC1fpMnBZOBDmueWA
|
16
|
+
B9EonmoO3ne7AJSgIvBbZzBPhzM4HrQGRW8LsPFsuj+dcJI43HOQwkmv2TRz0+t6
|
17
|
+
mGZldmqLcK0abv4JepLfB9XTue3kuyA29NGBibqyvRwlKckLpvKfHZX6Jxad8xxm
|
18
|
+
MbvRpzgROzyfw1qYi4dnIyMwTtXFFcZ0a2jpxHPkcTYFK6TzvFgDLAP0Y/u9jqUQ
|
19
|
+
eZ7/3CdSi/isZHEw
|
20
|
+
-----END CERTIFICATE-----
|
data/net-ssh.gemspec
CHANGED
@@ -2,15 +2,17 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: net-ssh 2.9.2.beta ruby lib
|
5
6
|
|
6
7
|
Gem::Specification.new do |s|
|
7
8
|
s.name = "net-ssh"
|
8
|
-
s.version = "2.9.
|
9
|
+
s.version = "2.9.2.beta"
|
9
10
|
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new("
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
11
13
|
s.authors = ["Jamis Buck", "Delano Mandelbaum"]
|
12
|
-
s.cert_chain = ["
|
13
|
-
s.date = "2014-
|
14
|
+
s.cert_chain = ["net-ssh-public_cert.pem"]
|
15
|
+
s.date = "2014-12-02"
|
14
16
|
s.description = "Net::SSH: a pure-Ruby implementation of the SSH2 client protocol. It allows you to write programs that invoke and interact with processes on remote servers, via SSH2."
|
15
17
|
s.email = "net-ssh@solutious.com"
|
16
18
|
s.extra_rdoc_files = [
|
@@ -26,7 +28,6 @@ Gem::Specification.new do |s|
|
|
26
28
|
"Rakefile",
|
27
29
|
"Rudyfile",
|
28
30
|
"THANKS.txt",
|
29
|
-
"gem-public_cert.pem",
|
30
31
|
"lib/net/ssh.rb",
|
31
32
|
"lib/net/ssh/authentication/agent.rb",
|
32
33
|
"lib/net/ssh/authentication/agent/java_pageant.rb",
|
@@ -46,6 +47,7 @@ Gem::Specification.new do |s|
|
|
46
47
|
"lib/net/ssh/config.rb",
|
47
48
|
"lib/net/ssh/connection/channel.rb",
|
48
49
|
"lib/net/ssh/connection/constants.rb",
|
50
|
+
"lib/net/ssh/connection/keepalive.rb",
|
49
51
|
"lib/net/ssh/connection/session.rb",
|
50
52
|
"lib/net/ssh/connection/term.rb",
|
51
53
|
"lib/net/ssh/errors.rb",
|
@@ -106,6 +108,7 @@ Gem::Specification.new do |s|
|
|
106
108
|
"lib/net/ssh/verifiers/secure.rb",
|
107
109
|
"lib/net/ssh/verifiers/strict.rb",
|
108
110
|
"lib/net/ssh/version.rb",
|
111
|
+
"net-ssh-public_cert.pem",
|
109
112
|
"net-ssh.gemspec",
|
110
113
|
"setup.rb",
|
111
114
|
"support/arcfour_check.rb",
|
@@ -177,14 +180,13 @@ Gem::Specification.new do |s|
|
|
177
180
|
]
|
178
181
|
s.homepage = "https://github.com/net-ssh/net-ssh"
|
179
182
|
s.licenses = ["MIT"]
|
180
|
-
s.require_paths = ["lib"]
|
181
183
|
s.rubyforge_project = "net-ssh"
|
182
|
-
s.rubygems_version = "
|
183
|
-
s.signing_key = "/mnt/gem/
|
184
|
+
s.rubygems_version = "2.2.2"
|
185
|
+
s.signing_key = "/mnt/gem/net-ssh-private_key.pem"
|
184
186
|
s.summary = "Net::SSH: a pure-Ruby implementation of the SSH2 client protocol."
|
185
187
|
|
186
188
|
if s.respond_to? :specification_version then
|
187
|
-
s.specification_version =
|
189
|
+
s.specification_version = 4
|
188
190
|
|
189
191
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
190
192
|
s.add_development_dependency(%q<test-unit>, [">= 0"])
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'common'
|
2
2
|
require 'net/ssh/authentication/methods/password'
|
3
|
+
require 'net/ssh/authentication/session'
|
3
4
|
require 'authentication/methods/common'
|
4
5
|
|
6
|
+
|
5
7
|
module Authentication; module Methods
|
6
8
|
|
7
9
|
class TestPassword < Test::Unit::TestCase
|
@@ -24,6 +26,47 @@ module Authentication; module Methods
|
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
29
|
+
def test_authenticate_ask_for_password_for_second_time_when_password_is_incorrect
|
30
|
+
transport.expect do |t,packet|
|
31
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
32
|
+
assert_equal "jamis", packet.read_string
|
33
|
+
assert_equal "ssh-connection", packet.read_string
|
34
|
+
assert_equal "password", packet.read_string
|
35
|
+
assert_equal false, packet.read_bool
|
36
|
+
assert_equal "the-password", packet.read_string
|
37
|
+
t.return(USERAUTH_FAILURE, :string, "publickey,password")
|
38
|
+
|
39
|
+
t.expect do |t2, packet2|
|
40
|
+
assert_equal USERAUTH_REQUEST, packet2.type
|
41
|
+
assert_equal "jamis", packet2.read_string
|
42
|
+
assert_equal "ssh-connection", packet2.read_string
|
43
|
+
assert_equal "password", packet2.read_string
|
44
|
+
assert_equal false, packet2.read_bool
|
45
|
+
assert_equal "the-password-2", packet2.read_string
|
46
|
+
t.return(USERAUTH_SUCCESS)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
subject.expects(:prompt).with("jamis@'s password:", false).returns("the-password-2")
|
51
|
+
subject.authenticate("ssh-connection", "jamis", "the-password")
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_authenticate_ask_for_password_if_not_given
|
55
|
+
transport.expect do |t,packet|
|
56
|
+
assert_equal USERAUTH_REQUEST, packet.type
|
57
|
+
assert_equal "bill", packet.read_string
|
58
|
+
assert_equal "ssh-connection", packet.read_string
|
59
|
+
assert_equal "password", packet.read_string
|
60
|
+
assert_equal false, packet.read_bool
|
61
|
+
assert_equal "good-password", packet.read_string
|
62
|
+
t.return(USERAUTH_SUCCESS)
|
63
|
+
end
|
64
|
+
|
65
|
+
transport.instance_eval { @host='testhost' }
|
66
|
+
subject.expects(:prompt).with("bill@testhost's password:", false).returns("good-password")
|
67
|
+
subject.authenticate("ssh-connection", "bill", nil)
|
68
|
+
end
|
69
|
+
|
27
70
|
def test_authenticate_when_password_is_acceptible_should_return_true
|
28
71
|
transport.expect do |t,packet|
|
29
72
|
assert_equal USERAUTH_REQUEST, packet.type
|
@@ -110,6 +110,25 @@ module Authentication
|
|
110
110
|
assert_equal "Okay, but not the best", result.last.comment
|
111
111
|
end
|
112
112
|
|
113
|
+
def test_identities_should_ignore_unimplemented_ones
|
114
|
+
key1 = key
|
115
|
+
key2 = OpenSSL::PKey::DSA.new(512)
|
116
|
+
key2.to_blob[0..5]='badkey'
|
117
|
+
key3 = OpenSSL::PKey::DSA.new(512)
|
118
|
+
|
119
|
+
socket.expect do |s, type, buffer|
|
120
|
+
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
|
121
|
+
s.return(SSH2_AGENT_IDENTITIES_ANSWER, :long, 3, :string, Net::SSH::Buffer.from(:key, key1), :string, "My favorite key", :string, Net::SSH::Buffer.from(:key, key2), :string, "bad", :string, Net::SSH::Buffer.from(:key, key3), :string, "Okay, but not the best")
|
122
|
+
end
|
123
|
+
|
124
|
+
result = agent.identities
|
125
|
+
assert_equal 2,result.size
|
126
|
+
assert_equal key1.to_blob, result.first.to_blob
|
127
|
+
assert_equal key3.to_blob, result.last.to_blob
|
128
|
+
assert_equal "My favorite key", result.first.comment
|
129
|
+
assert_equal "Okay, but not the best", result.last.comment
|
130
|
+
end
|
131
|
+
|
113
132
|
def test_close_should_close_socket
|
114
133
|
socket.expects(:close)
|
115
134
|
agent.close
|
@@ -366,12 +366,29 @@ module Connection
|
|
366
366
|
def test_process_should_call_enqueue_message_if_io_select_timed_out
|
367
367
|
timeout = Net::SSH::Connection::Session::DEFAULT_IO_SELECT_TIMEOUT
|
368
368
|
options = { :keepalive => true }
|
369
|
-
expected_packet = P(:byte, Net::SSH::Packet::
|
369
|
+
expected_packet = P(:byte, Net::SSH::Packet::GLOBAL_REQUEST, :string, "keepalive@openssh.com", :bool, true)
|
370
370
|
IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
|
371
|
-
transport.expects(:enqueue_message).with{ |msg| msg.content == expected_packet.content
|
371
|
+
transport.expects(:enqueue_message).with{ |msg| msg.content == expected_packet.content }
|
372
372
|
session(options).process
|
373
373
|
end
|
374
374
|
|
375
|
+
def test_process_should_raise_if_keepalives_not_answered
|
376
|
+
timeout = Net::SSH::Connection::Session::DEFAULT_IO_SELECT_TIMEOUT
|
377
|
+
options = { :keepalive => true, :keepalive_interval => 300, :keepalive_maxcount => 3 }
|
378
|
+
expected_packet = P(:byte, Net::SSH::Packet::GLOBAL_REQUEST, :string, "keepalive@openssh.com", :bool, true)
|
379
|
+
[1,2,3].each do |i|
|
380
|
+
Time.stubs(:now).returns(i*300)
|
381
|
+
IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
|
382
|
+
transport.expects(:enqueue_message).with{ |msg| msg.content == expected_packet.content }
|
383
|
+
session(options).process
|
384
|
+
end
|
385
|
+
|
386
|
+
Time.stubs(:now).returns(4*300)
|
387
|
+
IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
|
388
|
+
transport.expects(:enqueue_message).with{ |msg| msg.content == expected_packet.content }
|
389
|
+
assert_raises(Net::SSH::Timeout) { session(options).process }
|
390
|
+
end
|
391
|
+
|
375
392
|
def test_process_should_not_call_enqueue_message_unless_io_select_timed_out
|
376
393
|
timeout = Net::SSH::Connection::Session::DEFAULT_IO_SELECT_TIMEOUT
|
377
394
|
options = { :keepalive => true }
|
data/test/manual/test_forward.rb
CHANGED
@@ -3,15 +3,15 @@
|
|
3
3
|
# Tests for the following patch:
|
4
4
|
#
|
5
5
|
# http://github.com/net-ssh/net-ssh/tree/portfwfix
|
6
|
-
#
|
6
|
+
#
|
7
7
|
# It fixes 3 issues, regarding closing forwarded ports:
|
8
|
-
#
|
8
|
+
#
|
9
9
|
# 1.) if client closes a forwarded connection, but the server is reading, net-ssh terminates with IOError socket closed.
|
10
10
|
# 2.) if client force closes (RST) a forwarded connection, but server is reading, net-ssh terminates with
|
11
11
|
# 3.) if server closes the sending side, the on_eof is not handled.
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# More info:
|
14
|
-
#
|
14
|
+
#
|
15
15
|
# http://net-ssh.lighthouseapp.com/projects/36253/tickets/7
|
16
16
|
|
17
17
|
require 'common'
|
@@ -21,26 +21,26 @@ require 'timeout'
|
|
21
21
|
require 'tempfile'
|
22
22
|
|
23
23
|
class TestForward < Test::Unit::TestCase
|
24
|
-
|
24
|
+
|
25
25
|
def localhost
|
26
26
|
'localhost'
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def ssh_start_params
|
30
30
|
[localhost ,ENV['USER'], {:keys => "~/.ssh/id_rsa", :verbose => :debug}]
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def start_server_sending_lot_of_data(exceptions)
|
34
34
|
server = TCPServer.open(0)
|
35
35
|
Thread.start do
|
36
36
|
loop do
|
37
37
|
Thread.start(server.accept) do |client|
|
38
38
|
begin
|
39
|
-
10000.times do |i|
|
39
|
+
10000.times do |i|
|
40
40
|
client.puts "item#{i}"
|
41
41
|
end
|
42
42
|
client.close
|
43
|
-
rescue
|
43
|
+
rescue
|
44
44
|
exceptions << $!
|
45
45
|
raise
|
46
46
|
end
|
@@ -49,14 +49,14 @@ class TestForward < Test::Unit::TestCase
|
|
49
49
|
end
|
50
50
|
return server
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
def start_server_closing_soon(exceptions=nil)
|
54
54
|
server = TCPServer.open(0)
|
55
55
|
Thread.start do
|
56
56
|
loop do
|
57
57
|
Thread.start(server.accept) do |client|
|
58
58
|
begin
|
59
|
-
client.recv(1024)
|
59
|
+
client.recv(1024)
|
60
60
|
client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii"))
|
61
61
|
client.close
|
62
62
|
rescue
|
@@ -68,20 +68,20 @@ class TestForward < Test::Unit::TestCase
|
|
68
68
|
end
|
69
69
|
return server
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
def test_local_ephemeral_port_should_work_correctly
|
73
73
|
session = Net::SSH.start(*ssh_start_params)
|
74
|
-
|
74
|
+
|
75
75
|
assert_nothing_raised do
|
76
76
|
assigned_port = session.forward.local(0, localhost, 22)
|
77
77
|
assert_not_nil assigned_port
|
78
78
|
assert_operator assigned_port, :>, 0
|
79
79
|
end
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
82
|
def test_remote_ephemeral_port_should_work_correctly
|
83
83
|
session = Net::SSH.start(*ssh_start_params)
|
84
|
-
|
84
|
+
|
85
85
|
assert_nothing_raised do
|
86
86
|
session.forward.remote(22, localhost, 0, localhost)
|
87
87
|
session.loop { !(session.forward.active_remotes.length > 0) }
|
@@ -90,9 +90,58 @@ class TestForward < Test::Unit::TestCase
|
|
90
90
|
assert_operator assigned_port, :>, 0
|
91
91
|
end
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
|
+
def test_remote_callback_should_fire
|
95
|
+
session = Net::SSH.start(*ssh_start_params)
|
96
|
+
|
97
|
+
assert_nothing_raised do
|
98
|
+
got_port = nil
|
99
|
+
session.forward.remote(22, localhost, 0, localhost) do |port|
|
100
|
+
got_port = port
|
101
|
+
end
|
102
|
+
session.loop { !(session.forward.active_remotes.length > 0) }
|
103
|
+
assert_operator session.forward.active_remote_destinations.length, :==, 1
|
104
|
+
assert_operator session.forward.active_remote_destinations.keys.first, :==, [ 22, localhost ]
|
105
|
+
assert_operator session.forward.active_remote_destinations.values.first, :==, [ got_port, localhost ]
|
106
|
+
assert_operator session.forward.active_remotes.first, :==, [ got_port, localhost ]
|
107
|
+
assigned_port = session.forward.active_remotes.first[0]
|
108
|
+
assert_operator got_port, :==, assigned_port
|
109
|
+
assert_not_nil assigned_port
|
110
|
+
assert_operator assigned_port, :>, 0
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_remote_callback_should_fire_on_error_and_still_throw_exception
|
115
|
+
session = Net::SSH.start(*ssh_start_params)
|
116
|
+
|
117
|
+
assert_nothing_raised do
|
118
|
+
session.forward.remote(22, localhost, 22, localhost) do |port|
|
119
|
+
assert_operator port, :==, :error
|
120
|
+
end
|
121
|
+
end
|
122
|
+
assert_raises(Net::SSH::Exception) do
|
123
|
+
session.loop { true }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_remote_callback_should_fire_on_error_but_not_throw_exception_if_asked_not_to
|
128
|
+
session = Net::SSH.start(*ssh_start_params)
|
129
|
+
|
130
|
+
assert_nothing_raised do
|
131
|
+
got_port = nil
|
132
|
+
session.forward.remote(22, localhost, 22, localhost) do |port|
|
133
|
+
assert_operator port, :==, :error
|
134
|
+
got_port = port
|
135
|
+
:no_exception
|
136
|
+
end
|
137
|
+
session.loop { !got_port }
|
138
|
+
assert_operator port, :==, :error
|
139
|
+
assert_operator session.forward.active_remotes.length, :==, 0
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
94
143
|
def test_loop_should_not_abort_when_local_side_of_forward_is_closed
|
95
|
-
session = Net::SSH.start(*ssh_start_params)
|
144
|
+
session = Net::SSH.start(*ssh_start_params)
|
96
145
|
server_exc = Queue.new
|
97
146
|
server = start_server_sending_lot_of_data(server_exc)
|
98
147
|
remote_port = server.addr[1]
|
@@ -112,10 +161,10 @@ class TestForward < Test::Unit::TestCase
|
|
112
161
|
session.loop(0.1) { client_done.empty? }
|
113
162
|
assert_equal "Broken pipe", "#{server_exc.pop}" unless server_exc.empty?
|
114
163
|
end
|
115
|
-
|
164
|
+
|
116
165
|
def test_loop_should_not_abort_when_local_side_of_forward_is_reset
|
117
166
|
session = Net::SSH.start(*ssh_start_params)
|
118
|
-
server_exc = Queue.new
|
167
|
+
server_exc = Queue.new
|
119
168
|
server = start_server_sending_lot_of_data(server_exc)
|
120
169
|
remote_port = server.addr[1]
|
121
170
|
local_port = 0 # request ephemeral port
|
@@ -143,9 +192,9 @@ class TestForward < Test::Unit::TestCase
|
|
143
192
|
yield UNIXServer.open(path)
|
144
193
|
File.delete(path)
|
145
194
|
end if defined?(UNIXServer)
|
146
|
-
|
195
|
+
|
147
196
|
def test_forward_local_unix_socket_to_remote_port
|
148
|
-
session = Net::SSH.start(*ssh_start_params)
|
197
|
+
session = Net::SSH.start(*ssh_start_params)
|
149
198
|
server_exc = Queue.new
|
150
199
|
server = start_server_sending_lot_of_data(server_exc)
|
151
200
|
remote_port = server.addr[1]
|
@@ -174,7 +223,7 @@ class TestForward < Test::Unit::TestCase
|
|
174
223
|
end if defined?(UNIXSocket)
|
175
224
|
|
176
225
|
def test_loop_should_not_abort_when_server_side_of_forward_is_closed
|
177
|
-
session = Net::SSH.start(*ssh_start_params)
|
226
|
+
session = Net::SSH.start(*ssh_start_params)
|
178
227
|
server = start_server_closing_soon
|
179
228
|
remote_port = server.addr[1]
|
180
229
|
local_port = 0 # request ephemeral port
|
@@ -183,18 +232,18 @@ class TestForward < Test::Unit::TestCase
|
|
183
232
|
Thread.start do
|
184
233
|
begin
|
185
234
|
client = TCPSocket.new(localhost, local_port)
|
186
|
-
1.times do |i|
|
235
|
+
1.times do |i|
|
187
236
|
client.puts "item#{i}"
|
188
237
|
end
|
189
238
|
client.close
|
190
239
|
sleep(0.1)
|
191
|
-
ensure
|
240
|
+
ensure
|
192
241
|
client_done << true
|
193
242
|
end
|
194
243
|
end
|
195
244
|
session.loop(0.1) { client_done.empty? }
|
196
245
|
end
|
197
|
-
|
246
|
+
|
198
247
|
def start_server
|
199
248
|
server = TCPServer.open(0)
|
200
249
|
Thread.start do
|
@@ -206,9 +255,9 @@ class TestForward < Test::Unit::TestCase
|
|
206
255
|
end
|
207
256
|
return server
|
208
257
|
end
|
209
|
-
|
258
|
+
|
210
259
|
def test_server_eof_should_be_handled
|
211
|
-
session = Net::SSH.start(*ssh_start_params)
|
260
|
+
session = Net::SSH.start(*ssh_start_params)
|
212
261
|
server = start_server do |client|
|
213
262
|
client.write "This is a small message!"
|
214
263
|
client.close
|