net-ssh 2.9.1 → 2.9.2
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 +0 -0
- data/CHANGES.txt +17 -0
- data/README.rdoc +5 -0
- data/Rakefile +17 -4
- 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/channel.rb +1 -1
- data/lib/net/ssh/connection/keepalive.rb +55 -0
- data/lib/net/ssh/connection/session.rb +5 -23
- 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 +11 -11
- 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/lib/net/ssh.rb +10 -5
- 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/start/test_options.rb +7 -0
- 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
- data.tar.gz.sig +0 -0
- metadata +39 -50
- metadata.gz.sig +0 -0
- data/gem-public_cert.pem +0 -20
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: aac9757449c9d417f334f8a5c44b9b69105c4c9b
|
|
4
|
+
data.tar.gz: eda8ba20fad936162084101482eb1f1c821b67a3
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: fc1b60e3b51388d6b66fc38b7d4aaba56ead796820c2374a0aad1b48de094c2fb382db4159425d404f66612d8e61f0a1436b16dd90873235fcacca9b64bf3da5
|
|
7
|
+
data.tar.gz: f5dce76345e1774539a47d70c4f516e52164171d38da7569fd2f0489f34cc8599d0914115ad2108d89ca12cf667fa36a062a188508d3d136692075421d4e0307
|
checksums.yaml.gz.sig
ADDED
|
Binary file
|
data/CHANGES.txt
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
|
+
=== 2.9.2-rc3
|
|
1
2
|
|
|
3
|
+
* Remove advertised algorithms that were not working (curve25519-sha256@libssh.org) [mfazekas]
|
|
4
|
+
|
|
5
|
+
=== 2.9.2-rc2
|
|
6
|
+
|
|
7
|
+
* number_of_password_prompts is now accepted as ssh option, by setting it 0 net-ssh will not ask for password for password auth as with previous versions [mfazekas]
|
|
8
|
+
|
|
9
|
+
=== 2.9.2-rc1
|
|
10
|
+
|
|
11
|
+
* Documentation fixes and refactoring to keepalive [detiber, mfazekas]
|
|
12
|
+
|
|
13
|
+
=== 2.9.2-beta
|
|
14
|
+
|
|
15
|
+
* Remove advertised algorithms that were not working (ssh-rsa-cert-* *ed25519 acm*-gcm@openssh.com) [mfazekas]
|
|
16
|
+
* Unkown algorithms now ignored instead of failed [mfazekas]
|
|
17
|
+
* Asks for password with password auth (up to number_of_password_prompts) [mfazekas]
|
|
18
|
+
* Removed warnings [amatsuda]
|
|
2
19
|
|
|
3
20
|
=== 2.9.1 / 13 May 2014
|
|
4
21
|
|
data/README.rdoc
CHANGED
|
@@ -171,6 +171,11 @@ Run a single test file like this:
|
|
|
171
171
|
|
|
172
172
|
* JRuby 1.5: 99% tests pass (448 tests, 1846 assertions, 1 failures)
|
|
173
173
|
|
|
174
|
+
=== BUILDING GEM
|
|
175
|
+
|
|
176
|
+
Since building the gem requires the private key if you want to build a .gem locally please use the NET_SSH_NOKEY=1 envirnoment variable:
|
|
177
|
+
|
|
178
|
+
rake build NET_SSH_NOKEY=1
|
|
174
179
|
|
|
175
180
|
=== PORT FORWARDING TESTS
|
|
176
181
|
|
data/Rakefile
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# coding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Also in your terminal environment run:
|
|
4
|
+
# $ export LANG=en_US.UTF-8
|
|
5
|
+
# $ export LANGUAGE=en_US.UTF-8
|
|
6
|
+
# $ export LC_ALL=en_US.UTF-8
|
|
7
|
+
|
|
1
8
|
require "rubygems"
|
|
2
9
|
require "rake"
|
|
3
10
|
require "rake/clean"
|
|
@@ -21,7 +28,7 @@ begin
|
|
|
21
28
|
s.description = s.summary + " It allows you to write programs that invoke and interact with processes on remote servers, via SSH2."
|
|
22
29
|
s.email = "net-ssh@solutious.com"
|
|
23
30
|
s.homepage = "https://github.com/net-ssh/net-ssh"
|
|
24
|
-
s.authors = ["Jamis Buck", "Delano Mandelbaum"]
|
|
31
|
+
s.authors = ["Jamis Buck", "Delano Mandelbaum", "Miklós Fazekas"]
|
|
25
32
|
|
|
26
33
|
# Note: this is run at package time not install time so if you are
|
|
27
34
|
# running on jruby, you need to install jruby-pageant manually.
|
|
@@ -34,10 +41,16 @@ begin
|
|
|
34
41
|
|
|
35
42
|
s.license = "MIT"
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
unless ENV['NET_SSH_NOKEY']
|
|
45
|
+
signing_key = File.join('/mnt/gem/', 'net-ssh-private_key.pem')
|
|
46
|
+
s.signing_key = File.join('/mnt/gem/', 'net-ssh-private_key.pem')
|
|
47
|
+
s.cert_chain = ['net-ssh-public_cert.pem']
|
|
48
|
+
unless (Rake.application.top_level_tasks & ['build','install']).empty?
|
|
49
|
+
raise "No key found at #{signing_key} for signing, use rake <taskname> NET_SSH_NOKEY=1 to build without key" unless File.exist?(signing_key)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
39
52
|
end
|
|
40
|
-
Jeweler::
|
|
53
|
+
Jeweler::RubygemsDotOrgTasks.new
|
|
41
54
|
rescue LoadError
|
|
42
55
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
|
43
56
|
end
|
|
@@ -94,10 +94,16 @@ module Net; module SSH; module Authentication
|
|
|
94
94
|
|
|
95
95
|
identities = []
|
|
96
96
|
body.read_long.times do
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
key_str = body.read_string
|
|
98
|
+
comment_str = body.read_string
|
|
99
|
+
begin
|
|
100
|
+
key = Buffer.new(key_str).read_key
|
|
101
|
+
key.extend(Comment)
|
|
102
|
+
key.comment = comment_str
|
|
103
|
+
identities.push key
|
|
104
|
+
rescue NotImplementedError => e
|
|
105
|
+
error { "ignoring unimplemented key:#{e.message} #{comment_str}" }
|
|
106
|
+
end
|
|
101
107
|
end
|
|
102
108
|
|
|
103
109
|
return identities
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'net/ssh/errors'
|
|
2
|
+
require 'net/ssh/prompt'
|
|
2
3
|
require 'net/ssh/authentication/methods/abstract'
|
|
3
4
|
|
|
4
5
|
module Net
|
|
@@ -8,25 +9,36 @@ module Net
|
|
|
8
9
|
|
|
9
10
|
# Implements the "password" SSH authentication method.
|
|
10
11
|
class Password < Abstract
|
|
12
|
+
include Prompt
|
|
13
|
+
|
|
11
14
|
# Attempt to authenticate the given user for the given service. If
|
|
12
|
-
# the password parameter is nil, this will
|
|
13
|
-
# return false.
|
|
15
|
+
# the password parameter is nil, this will ask for password
|
|
14
16
|
def authenticate(next_service, username, password=nil)
|
|
15
|
-
|
|
17
|
+
retries = 0
|
|
18
|
+
max_retries = get_max_retries
|
|
19
|
+
return false if !password && max_retries == 0
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
begin
|
|
22
|
+
password_to_send = password || ask_password(username)
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
send_message(userauth_request(username, next_service, "password", false, password_to_send))
|
|
25
|
+
message = session.next_message
|
|
26
|
+
retries += 1
|
|
27
|
+
|
|
28
|
+
if message.type == USERAUTH_FAILURE
|
|
25
29
|
debug { "password failed" }
|
|
26
30
|
|
|
27
31
|
raise Net::SSH::Authentication::DisallowedMethod unless
|
|
28
32
|
message[:authentications].split(/,/).include? 'password'
|
|
33
|
+
password = nil
|
|
34
|
+
end
|
|
35
|
+
end until (message.type != USERAUTH_FAILURE || retries >= max_retries)
|
|
29
36
|
|
|
37
|
+
case message.type
|
|
38
|
+
when USERAUTH_SUCCESS
|
|
39
|
+
debug { "password succeeded" }
|
|
40
|
+
return true
|
|
41
|
+
when USERAUTH_FAILURE
|
|
30
42
|
return false
|
|
31
43
|
when USERAUTH_PASSWD_CHANGEREQ
|
|
32
44
|
debug { "password change request received, failing" }
|
|
@@ -35,6 +47,19 @@ module Net
|
|
|
35
47
|
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
|
36
48
|
end
|
|
37
49
|
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
NUMBER_OF_PASSWORD_PROMPTS = 3
|
|
54
|
+
|
|
55
|
+
def ask_password(username)
|
|
56
|
+
echo = false
|
|
57
|
+
prompt("#{username}@#{session.transport.host}'s password:", echo)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def get_max_retries
|
|
61
|
+
(session.transport.options||{})[:number_of_password_prompts] || NUMBER_OF_PASSWORD_PROMPTS
|
|
62
|
+
end
|
|
38
63
|
end
|
|
39
64
|
|
|
40
65
|
end
|
data/lib/net/ssh/buffer.rb
CHANGED
|
@@ -255,7 +255,7 @@ module Net; module SSH
|
|
|
255
255
|
key.e = read_bignum
|
|
256
256
|
key.n = read_bignum
|
|
257
257
|
|
|
258
|
-
when /^ecdsa\-sha2\-(\w*)
|
|
258
|
+
when /^ecdsa\-sha2\-(\w*)$/
|
|
259
259
|
unless defined?(OpenSSL::PKey::EC)
|
|
260
260
|
raise NotImplementedError, "unsupported key type `#{type}'"
|
|
261
261
|
else
|
data/lib/net/ssh/config.rb
CHANGED
|
@@ -31,6 +31,7 @@ module Net; module SSH
|
|
|
31
31
|
# * RekeyLimit => :rekey_limit
|
|
32
32
|
# * User => :user
|
|
33
33
|
# * UserKnownHostsFile => :user_known_hosts_file
|
|
34
|
+
# * NumberOfPasswordPrompts => :number_of_password_prompts
|
|
34
35
|
#
|
|
35
36
|
# Note that you will never need to use this class directly--you can control
|
|
36
37
|
# whether the OpenSSH configuration files are read by passing the :config
|
|
@@ -59,7 +60,7 @@ module Net; module SSH
|
|
|
59
60
|
# #default_files), translates the resulting hash into the options
|
|
60
61
|
# recognized by Net::SSH, and returns them.
|
|
61
62
|
def for(host, files=default_files)
|
|
62
|
-
|
|
63
|
+
translate(files.inject({}) { |settings, file|
|
|
63
64
|
load(file, host, settings)
|
|
64
65
|
})
|
|
65
66
|
end
|
|
@@ -76,7 +77,6 @@ module Net; module SSH
|
|
|
76
77
|
|
|
77
78
|
globals = {}
|
|
78
79
|
matched_host = nil
|
|
79
|
-
multi_host = []
|
|
80
80
|
seen_host = false
|
|
81
81
|
IO.foreach(file) do |line|
|
|
82
82
|
next if line =~ /^\s*(?:#.*)?$/
|
|
@@ -220,6 +220,8 @@ module Net; module SSH
|
|
|
220
220
|
when 'sendenv'
|
|
221
221
|
multi_send_env = value.to_s.split(/\s+/)
|
|
222
222
|
hash[:send_env] = multi_send_env.map { |e| Regexp.new pattern2regex(e).source, false }
|
|
223
|
+
when 'numberofpasswordprompts'
|
|
224
|
+
hash[:number_of_password_prompts] = value.to_i
|
|
223
225
|
end
|
|
224
226
|
hash
|
|
225
227
|
end
|
|
@@ -523,7 +523,7 @@ module Net; module SSH; module Connection
|
|
|
523
523
|
@on_open_failed.call(self, reason_code, description)
|
|
524
524
|
else
|
|
525
525
|
raise ChannelOpenFailed.new(reason_code, description)
|
|
526
|
-
end
|
|
526
|
+
end
|
|
527
527
|
end
|
|
528
528
|
|
|
529
529
|
# Invoked when the server sends a CHANNEL_WINDOW_ADJUST packet, and
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'net/ssh/loggable'
|
|
2
|
+
module Net; module SSH; module Connection
|
|
3
|
+
|
|
4
|
+
class Keepalive
|
|
5
|
+
include Loggable
|
|
6
|
+
|
|
7
|
+
def initialize(session)
|
|
8
|
+
@last_keepalive_sent_at = nil
|
|
9
|
+
@unresponded_keepalive_count = 0
|
|
10
|
+
@session = session
|
|
11
|
+
self.logger = session.logger
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def options
|
|
15
|
+
@session.options
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def enabled?
|
|
19
|
+
options[:keepalive]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def interval
|
|
23
|
+
options[:keepalive_interval] || Session::DEFAULT_IO_SELECT_TIMEOUT
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def should_send?
|
|
27
|
+
return false unless enabled?
|
|
28
|
+
return true unless @last_keepalive_sent_at
|
|
29
|
+
Time.now - @last_keepalive_sent_at >= interval
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def keepalive_maxcount
|
|
33
|
+
(options[:keepalive_maxcount] || 3).to_i
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def send_as_needed(readers, writers)
|
|
37
|
+
return unless readers.nil? && writers.nil?
|
|
38
|
+
return unless should_send?
|
|
39
|
+
info { "sending keepalive #{@unresponded_keepalive_count}" }
|
|
40
|
+
|
|
41
|
+
@unresponded_keepalive_count += 1
|
|
42
|
+
@session.send_global_request("keepalive@openssh.com") { |success, response|
|
|
43
|
+
debug { "keepalive response successful. Missed #{@unresponded_keepalive_count-1} keepalives" }
|
|
44
|
+
@unresponded_keepalive_count = 0
|
|
45
|
+
}
|
|
46
|
+
@last_keepalive_sent_at = Time.now
|
|
47
|
+
if keepalive_maxcount > 0 && @unresponded_keepalive_count > keepalive_maxcount
|
|
48
|
+
error { "Timeout, server #{@session.host} not responding. Missed #{@unresponded_keepalive_count-1} timeouts." }
|
|
49
|
+
@unresponded_keepalive_count = 0
|
|
50
|
+
raise Net::SSH::Timeout, "Timeout, server #{@session.host} not responding."
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end; end; end
|
|
@@ -3,6 +3,7 @@ require 'net/ssh/ruby_compat'
|
|
|
3
3
|
require 'net/ssh/connection/channel'
|
|
4
4
|
require 'net/ssh/connection/constants'
|
|
5
5
|
require 'net/ssh/service/forward'
|
|
6
|
+
require 'net/ssh/connection/keepalive'
|
|
6
7
|
|
|
7
8
|
module Net; module SSH; module Connection
|
|
8
9
|
|
|
@@ -79,7 +80,7 @@ module Net; module SSH; module Connection
|
|
|
79
80
|
@max_pkt_size = (options.has_key?(:max_pkt_size) ? options[:max_pkt_size] : 0x8000)
|
|
80
81
|
@max_win_size = (options.has_key?(:max_win_size) ? options[:max_win_size] : 0x20000)
|
|
81
82
|
|
|
82
|
-
@
|
|
83
|
+
@keepalive = Keepalive.new(self)
|
|
83
84
|
end
|
|
84
85
|
|
|
85
86
|
# Retrieves a custom property from this instance. This can be used to
|
|
@@ -244,7 +245,7 @@ module Net; module SSH; module Connection
|
|
|
244
245
|
writer.send_pending
|
|
245
246
|
end
|
|
246
247
|
|
|
247
|
-
|
|
248
|
+
@keepalive.send_as_needed(readers, writers)
|
|
248
249
|
transport.rekey_as_needed
|
|
249
250
|
|
|
250
251
|
return true
|
|
@@ -598,27 +599,8 @@ module Net; module SSH; module Connection
|
|
|
598
599
|
|
|
599
600
|
def io_select_wait(wait)
|
|
600
601
|
return wait if wait
|
|
601
|
-
return wait unless
|
|
602
|
-
|
|
603
|
-
end
|
|
604
|
-
|
|
605
|
-
def keepalive_interval
|
|
606
|
-
options[:keepalive_interval] || DEFAULT_IO_SELECT_TIMEOUT
|
|
607
|
-
end
|
|
608
|
-
|
|
609
|
-
def should_send_keepalive?
|
|
610
|
-
return false unless options[:keepalive]
|
|
611
|
-
return true unless @last_keepalive_sent_at
|
|
612
|
-
Time.now - @last_keepalive_sent_at >= keepalive_interval
|
|
613
|
-
end
|
|
614
|
-
|
|
615
|
-
def send_keepalive_as_needed(readers, writers)
|
|
616
|
-
return unless readers.nil? && writers.nil?
|
|
617
|
-
return unless should_send_keepalive?
|
|
618
|
-
info { "sending keepalive" }
|
|
619
|
-
msg = Net::SSH::Buffer.from(:byte, Packet::IGNORE, :string, "keepalive")
|
|
620
|
-
send_message(msg)
|
|
621
|
-
@last_keepalive_sent_at = Time.now
|
|
602
|
+
return wait unless @keepalive.enabled?
|
|
603
|
+
@keepalive.interval
|
|
622
604
|
end
|
|
623
605
|
|
|
624
606
|
MAP = Constants.constants.inject({}) do |memo, name|
|
data/lib/net/ssh/errors.rb
CHANGED
|
@@ -14,6 +14,10 @@ module Net; module SSH
|
|
|
14
14
|
# unexpectedly.
|
|
15
15
|
class Disconnect < Exception; end
|
|
16
16
|
|
|
17
|
+
# This exception is raised when the remote host has disconnected/
|
|
18
|
+
# timeouted unexpectedly.
|
|
19
|
+
class Timeout < Disconnect; end
|
|
20
|
+
|
|
17
21
|
# This exception is primarily used internally, but if you have a channel
|
|
18
22
|
# request handler (see Net::SSH::Connection::Channel#on_request) that you
|
|
19
23
|
# want to fail in such a way that the server knows it failed, you can
|
data/lib/net/ssh/known_hosts.rb
CHANGED
|
@@ -15,17 +15,9 @@ module Net; module SSH
|
|
|
15
15
|
SUPPORTED_TYPE = %w(ssh-rsa ssh-dss
|
|
16
16
|
ecdsa-sha2-nistp256
|
|
17
17
|
ecdsa-sha2-nistp384
|
|
18
|
-
ecdsa-sha2-nistp521
|
|
19
|
-
ssh-ed25519-cert-v01@openssh.com
|
|
20
|
-
ssh-rsa-cert-v01@openssh.com
|
|
21
|
-
ssh-rsa-cert-v00@openssh.com
|
|
22
|
-
ssh-ed25519
|
|
23
|
-
)
|
|
18
|
+
ecdsa-sha2-nistp521)
|
|
24
19
|
else
|
|
25
|
-
SUPPORTED_TYPE = %w(ssh-rsa ssh-dss
|
|
26
|
-
ssh-rsa-cert-v01@openssh.com
|
|
27
|
-
ssh-rsa-cert-v00@openssh.com
|
|
28
|
-
)
|
|
20
|
+
SUPPORTED_TYPE = %w(ssh-rsa ssh-dss)
|
|
29
21
|
end
|
|
30
22
|
|
|
31
23
|
|
|
@@ -88,13 +88,13 @@ module Net; module SSH; module Service
|
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
prepare_client(client, channel, :local)
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
channel.on_open_failed do |ch, code, description|
|
|
93
93
|
channel.error { "could not establish direct channel: #{description} (#{code})" }
|
|
94
94
|
channel[:socket].close
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
local_port
|
|
99
99
|
end
|
|
100
100
|
|
|
@@ -131,22 +131,52 @@ module Net; module SSH; module Service
|
|
|
131
131
|
# the port number. The assigned port will show up in the # #active_remotes
|
|
132
132
|
# list.
|
|
133
133
|
#
|
|
134
|
+
# remote_host is interpreted by the server per RFC 4254, which has these
|
|
135
|
+
# special values:
|
|
136
|
+
#
|
|
137
|
+
# - "" means that connections are to be accepted on all protocol
|
|
138
|
+
# families supported by the SSH implementation.
|
|
139
|
+
# - "0.0.0.0" means to listen on all IPv4 addresses.
|
|
140
|
+
# - "::" means to listen on all IPv6 addresses.
|
|
141
|
+
# - "localhost" means to listen on all protocol families supported by
|
|
142
|
+
# the SSH implementation on loopback addresses only ([RFC3330] and
|
|
143
|
+
# [RFC3513]).
|
|
144
|
+
# - "127.0.0.1" and "::1" indicate listening on the loopback
|
|
145
|
+
# interfaces for IPv4 and IPv6, respectively.
|
|
146
|
+
#
|
|
147
|
+
# You may pass a block that will be called when the the port forward
|
|
148
|
+
# request receives a response. This block will be passed the remote_port
|
|
149
|
+
# that was actually bound to, or nil if the binding failed. If the block
|
|
150
|
+
# returns :no_exception, the "failed binding" exception will not be thrown.
|
|
151
|
+
#
|
|
134
152
|
# If you want to block until the port is active, you could do something
|
|
135
153
|
# like this:
|
|
136
154
|
#
|
|
137
|
-
#
|
|
138
|
-
#
|
|
139
|
-
#
|
|
140
|
-
#
|
|
155
|
+
# got_remote_port = nil
|
|
156
|
+
# remote(port, host, remote_port, remote_host) do |actual_remote_port|
|
|
157
|
+
# got_remote_port = actual_remote_port || :error
|
|
158
|
+
# :no_exception # will yield the exception on my own thread
|
|
159
|
+
# end
|
|
160
|
+
# session.loop { !got_remote_port }
|
|
161
|
+
# if got_remote_port == :error
|
|
162
|
+
# raise Net::SSH::Exception, "remote forwarding request failed"
|
|
163
|
+
# end
|
|
164
|
+
#
|
|
141
165
|
def remote(port, host, remote_port, remote_host="127.0.0.1")
|
|
142
166
|
session.send_global_request("tcpip-forward", :string, remote_host, :long, remote_port) do |success, response|
|
|
143
167
|
if success
|
|
144
168
|
remote_port = response.read_long if remote_port == 0
|
|
145
169
|
debug { "remote forward from remote #{remote_host}:#{remote_port} to #{host}:#{port} established" }
|
|
146
170
|
@remote_forwarded_ports[[remote_port, remote_host]] = Remote.new(host, port)
|
|
171
|
+
yield remote_port, remote_host if block_given?
|
|
147
172
|
else
|
|
148
|
-
|
|
149
|
-
|
|
173
|
+
instruction = if block_given?
|
|
174
|
+
yield :error
|
|
175
|
+
end
|
|
176
|
+
unless instruction == :no_exception
|
|
177
|
+
error { "remote forwarding request failed" }
|
|
178
|
+
raise Net::SSH::Exception, "remote forwarding request failed"
|
|
179
|
+
end
|
|
150
180
|
end
|
|
151
181
|
end
|
|
152
182
|
end
|
|
@@ -183,6 +213,16 @@ module Net; module SSH; module Service
|
|
|
183
213
|
@remote_forwarded_ports.keys
|
|
184
214
|
end
|
|
185
215
|
|
|
216
|
+
# Returns all active remote forwarded ports and where they forward to. The
|
|
217
|
+
# returned value is a hash from [<forwarding port on the local host>, <local forwarding address>]
|
|
218
|
+
# to [<port on the remote host>, <remote bind address>].
|
|
219
|
+
def active_remote_destinations
|
|
220
|
+
@remote_forwarded_ports.inject({}) do |result, (remote, local)|
|
|
221
|
+
result[[local.port, local.host]] = remote
|
|
222
|
+
result
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
186
226
|
# Enables SSH agent forwarding on the given channel. The forwarded agent
|
|
187
227
|
# will remain active even after the channel closes--the channel is only
|
|
188
228
|
# used as the transport for enabling the forwarded connection. You should
|
|
@@ -216,7 +256,7 @@ module Net; module SSH; module Service
|
|
|
216
256
|
end
|
|
217
257
|
|
|
218
258
|
private
|
|
219
|
-
|
|
259
|
+
|
|
220
260
|
# Perform setup operations that are common to all forwarded channels.
|
|
221
261
|
# +client+ is a socket, +channel+ is the channel that was just created,
|
|
222
262
|
# and +type+ is an arbitrary string describing the type of the channel.
|
|
@@ -228,11 +268,11 @@ module Net; module SSH; module Service
|
|
|
228
268
|
session.listen_to(client)
|
|
229
269
|
channel[:socket] = client
|
|
230
270
|
|
|
231
|
-
channel.on_data do |ch, data|
|
|
271
|
+
channel.on_data do |ch, data|
|
|
232
272
|
debug { "data:#{data.length} on #{type} forwarded channel" }
|
|
233
273
|
ch[:socket].enqueue(data)
|
|
234
274
|
end
|
|
235
|
-
|
|
275
|
+
|
|
236
276
|
# Handles server close on the sending side by Miklós Fazekas
|
|
237
277
|
channel.on_eof do |ch|
|
|
238
278
|
debug { "eof #{type} on #{type} forwarded channel" }
|
|
@@ -251,7 +291,7 @@ module Net; module SSH; module Service
|
|
|
251
291
|
debug { "enotconn in on_eof => shallowing exception:#{e}" }
|
|
252
292
|
end
|
|
253
293
|
end
|
|
254
|
-
|
|
294
|
+
|
|
255
295
|
channel.on_close do |ch|
|
|
256
296
|
debug { "closing #{type} forwarded channel" }
|
|
257
297
|
ch[:socket].close if !client.closed?
|
|
@@ -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,13 +55,10 @@ 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
|
-
ecdh-sha2-nistp521
|
|
66
|
-
curve25519-sha256@libssh.org)
|
|
61
|
+
ecdh-sha2-nistp521)
|
|
67
62
|
end
|
|
68
63
|
|
|
69
64
|
# The underlying transport layer session that supports this object
|
|
@@ -221,8 +216,13 @@ module Net; module SSH; module Transport
|
|
|
221
216
|
# apply the preferred algorithm order, if any
|
|
222
217
|
if options[algorithm]
|
|
223
218
|
algorithms[algorithm] = Array(options[algorithm]).compact.uniq
|
|
224
|
-
|
|
225
|
-
|
|
219
|
+
unsupported = []
|
|
220
|
+
algorithms[algorithm].select! do |name|
|
|
221
|
+
supported = ALGORITHMS[algorithm].include?(name)
|
|
222
|
+
unsupported << name unless supported
|
|
223
|
+
supported
|
|
224
|
+
end
|
|
225
|
+
lwarn { "unsupported #{algorithm} algorithm: `#{unsupported}'" } unless unsupported.empty?
|
|
226
226
|
|
|
227
227
|
# make sure all of our supported algorithms are tacked onto the
|
|
228
228
|
# 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 = nil
|
|
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
|