net-ssh 2.6.8 → 2.7.0
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.
- data/CHANGES.txt +9 -0
- data/lib/net/ssh.rb +10 -2
- data/lib/net/ssh/authentication/key_manager.rb +3 -0
- data/lib/net/ssh/config.rb +3 -0
- data/lib/net/ssh/connection/channel.rb +20 -0
- data/lib/net/ssh/connection/session.rb +32 -1
- data/lib/net/ssh/proxy/http.rb +1 -1
- data/lib/net/ssh/version.rb +2 -2
- data/net-ssh.gemspec +4 -2
- data/test/configs/send_env +2 -0
- data/test/connection/test_session.rb +38 -0
- data/test/start/test_options.rb +36 -0
- data/test/test_config.rb +10 -2
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +1 -0
- data/test/transport/kex/test_ecdh_sha2_nistp384.rb +1 -0
- data/test/transport/kex/test_ecdh_sha2_nistp521.rb +1 -0
- metadata +4 -2
data/CHANGES.txt
CHANGED
@@ -1,4 +1,13 @@
|
|
1
1
|
|
2
|
+
|
3
|
+
=== 2.7.0 / 11 Sep 2013
|
4
|
+
|
5
|
+
* Fix for 'Could not parse PKey: no start line' error on private keys with passphrases (issue #101) [metametaclass]
|
6
|
+
* Automatically forward environment variables defined in OpenSSH config files [fnordfish]
|
7
|
+
* Guard against socket.gets being nil in Net::SSH::Proxy::HTTP [krishicks]
|
8
|
+
* Implemented experimental keepalive feature [noric]
|
9
|
+
|
10
|
+
|
2
11
|
=== 2.6.8 / 6 Jul 2013
|
3
12
|
|
4
13
|
* Added support for host wildcard substitution [GabKlein]
|
data/lib/net/ssh.rb
CHANGED
@@ -62,12 +62,13 @@ module Net
|
|
62
62
|
# Net::SSH.start for a description of each option.
|
63
63
|
VALID_OPTIONS = [
|
64
64
|
:auth_methods, :bind_address, :compression, :compression_level, :config,
|
65
|
-
:encryption, :forward_agent, :hmac, :host_key,
|
65
|
+
:encryption, :forward_agent, :hmac, :host_key,
|
66
|
+
:keepalive, :keepalive_interval, :kex, :keys, :key_data,
|
66
67
|
:languages, :logger, :paranoid, :password, :port, :proxy,
|
67
68
|
:rekey_blocks_limit,:rekey_limit, :rekey_packet_limit, :timeout, :verbose,
|
68
69
|
:global_known_hosts_file, :user_known_hosts_file, :host_key_alias,
|
69
70
|
:host_name, :user, :properties, :passphrase, :keys_only, :max_pkt_size,
|
70
|
-
:max_win_size
|
71
|
+
:max_win_size, :send_env
|
71
72
|
]
|
72
73
|
|
73
74
|
# The standard means of starting a new SSH connection. When used with a
|
@@ -124,6 +125,11 @@ module Net
|
|
124
125
|
# specified in an SSH configuration file. It lets you specify an
|
125
126
|
# "alias", similarly to adding an entry in /etc/hosts but without needing
|
126
127
|
# to modify /etc/hosts.
|
128
|
+
# :keepalive => set to +true+ to send a keepalive packet to the SSH server
|
129
|
+
# when there's no traffic between the SSH server and Net::SSH client for
|
130
|
+
# the keepalive_interval seconds. Defaults to +false+.
|
131
|
+
# :keepalive_interval => the interval seconds for keepalive.
|
132
|
+
# Defaults to +300+ seconds.
|
127
133
|
# * :kex => the key exchange algorithm (or algorithms) to use
|
128
134
|
# * :keys => an array of file names of private keys to use for publickey
|
129
135
|
# and hostbased authentication
|
@@ -151,6 +157,8 @@ module Net
|
|
151
157
|
# * :rekey_blocks_limit => the max number of blocks to process before rekeying
|
152
158
|
# * :rekey_limit => the max number of bytes to process before rekeying
|
153
159
|
# * :rekey_packet_limit => the max number of packets to process before rekeying
|
160
|
+
# * :send_env => an array of local environment variable names to export to the
|
161
|
+
# remote environment. Names may be given as String or Regexp.
|
154
162
|
# * :timeout => how long to wait for the initial connection to be made
|
155
163
|
# * :user => the user name to log in as; this overrides the +user+
|
156
164
|
# parameter, and is primarily only useful when provided via an SSH
|
data/lib/net/ssh/config.rb
CHANGED
@@ -176,6 +176,9 @@ module Net; module SSH
|
|
176
176
|
hash[:user] = value
|
177
177
|
when 'userknownhostsfile'
|
178
178
|
hash[:user_known_hosts_file] = value
|
179
|
+
when 'sendenv'
|
180
|
+
multi_send_env = value.to_s.split(/\s+/)
|
181
|
+
hash[:send_env] = multi_send_env.map { |e| Regexp.new pattern2regex(e).source, false }
|
179
182
|
end
|
180
183
|
hash
|
181
184
|
end
|
@@ -510,6 +510,7 @@ module Net; module SSH; module Connection
|
|
510
510
|
@remote_window_size = @remote_maximum_window_size = max_window
|
511
511
|
@remote_maximum_packet_size = max_packet
|
512
512
|
connection.forward.agent(self) if connection.options[:forward_agent] && type == "session"
|
513
|
+
forward_local_env(connection.options[:send_env]) if connection.options[:send_env]
|
513
514
|
@on_confirm_open.call(self) if @on_confirm_open
|
514
515
|
end
|
515
516
|
|
@@ -625,6 +626,25 @@ module Net; module SSH; module Connection
|
|
625
626
|
@local_maximum_window_size += 0x20000
|
626
627
|
end
|
627
628
|
end
|
629
|
+
|
630
|
+
# Gets an +Array+ of local environment variables in the remote process'
|
631
|
+
# environment.
|
632
|
+
# A variable name can either be described by a +Regexp+ or +String+.
|
633
|
+
#
|
634
|
+
# channel.forward_local_env [/^GIT_.*$/, "LANG"]
|
635
|
+
def forward_local_env(env_variable_patterns)
|
636
|
+
Array(env_variable_patterns).each do |env_variable_pattern|
|
637
|
+
matched_variables = ENV.find_all do |env_name, _|
|
638
|
+
case env_variable_pattern
|
639
|
+
when Regexp then env_name =~ env_variable_pattern
|
640
|
+
when String then env_name == env_variable_pattern
|
641
|
+
end
|
642
|
+
end
|
643
|
+
matched_variables.each do |env_name, env_value|
|
644
|
+
self.env(env_name, env_value)
|
645
|
+
end
|
646
|
+
end
|
647
|
+
end
|
628
648
|
end
|
629
649
|
|
630
650
|
end; end; end
|
@@ -25,6 +25,9 @@ module Net; module SSH; module Connection
|
|
25
25
|
class Session
|
26
26
|
include Constants, Loggable
|
27
27
|
|
28
|
+
# Default IO.select timeout threshold
|
29
|
+
DEFAULT_IO_SELECT_TIMEOUT = 300
|
30
|
+
|
28
31
|
# The underlying transport layer abstraction (see Net::SSH::Transport::Session).
|
29
32
|
attr_reader :transport
|
30
33
|
|
@@ -75,6 +78,8 @@ module Net; module SSH; module Connection
|
|
75
78
|
|
76
79
|
@max_pkt_size = (options.has_key?(:max_pkt_size) ? options[:max_pkt_size] : 0x8000)
|
77
80
|
@max_win_size = (options.has_key?(:max_win_size) ? options[:max_win_size] : 0x20000)
|
81
|
+
|
82
|
+
@last_keepalive_sent_at = nil
|
78
83
|
end
|
79
84
|
|
80
85
|
# Retrieves a custom property from this instance. This can be used to
|
@@ -201,7 +206,7 @@ module Net; module SSH; module Connection
|
|
201
206
|
|
202
207
|
r = listeners.keys
|
203
208
|
w = r.select { |w2| w2.respond_to?(:pending_write?) && w2.pending_write? }
|
204
|
-
readers, writers, = Net::SSH::Compat.io_select(r, w, nil, wait)
|
209
|
+
readers, writers, = Net::SSH::Compat.io_select(r, w, nil, io_select_wait(wait))
|
205
210
|
|
206
211
|
postprocess(readers, writers)
|
207
212
|
end
|
@@ -239,6 +244,7 @@ module Net; module SSH; module Connection
|
|
239
244
|
writer.send_pending
|
240
245
|
end
|
241
246
|
|
247
|
+
send_keepalive_as_needed(readers, writers)
|
242
248
|
transport.rekey_as_needed
|
243
249
|
|
244
250
|
return true
|
@@ -590,6 +596,31 @@ module Net; module SSH; module Connection
|
|
590
596
|
channels[packet[:local_id]].do_failure
|
591
597
|
end
|
592
598
|
|
599
|
+
def io_select_wait(wait)
|
600
|
+
return wait if wait
|
601
|
+
return wait unless options[:keepalive]
|
602
|
+
keepalive_interval
|
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
|
622
|
+
end
|
623
|
+
|
593
624
|
MAP = Constants.constants.inject({}) do |memo, name|
|
594
625
|
value = const_get(name)
|
595
626
|
next unless Integer === value
|
data/lib/net/ssh/proxy/http.rb
CHANGED
@@ -73,7 +73,7 @@ module Net; module SSH; module Proxy
|
|
73
73
|
version, code, reason = socket.gets.chomp.split(/ /, 3)
|
74
74
|
headers = {}
|
75
75
|
|
76
|
-
while (line = socket.gets.chomp
|
76
|
+
while (line = socket.gets) && (line.chomp! != "")
|
77
77
|
name, value = line.split(/:/, 2)
|
78
78
|
headers[name.strip] = value.strip
|
79
79
|
end
|
data/lib/net/ssh/version.rb
CHANGED
@@ -48,10 +48,10 @@ module Net; module SSH
|
|
48
48
|
MAJOR = 2
|
49
49
|
|
50
50
|
# The minor component of this version of the Net::SSH library
|
51
|
-
MINOR =
|
51
|
+
MINOR = 7
|
52
52
|
|
53
53
|
# The tiny component of this version of the Net::SSH library
|
54
|
-
TINY =
|
54
|
+
TINY = 0
|
55
55
|
|
56
56
|
# The current version of the Net::SSH library as a Version instance
|
57
57
|
CURRENT = new(MAJOR, MINOR, TINY)
|
data/net-ssh.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "net-ssh"
|
8
|
-
s.version = "2.
|
8
|
+
s.version = "2.7.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jamis Buck", "Delano Mandelbaum"]
|
12
|
-
s.date = "2013-
|
12
|
+
s.date = "2013-09-11"
|
13
13
|
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."
|
14
14
|
s.email = "net-ssh@solutious.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -126,12 +126,14 @@ Gem::Specification.new do |s|
|
|
126
126
|
"test/configs/multihost",
|
127
127
|
"test/configs/nohost",
|
128
128
|
"test/configs/numeric_host",
|
129
|
+
"test/configs/send_env",
|
129
130
|
"test/configs/substitutes",
|
130
131
|
"test/configs/wild_cards",
|
131
132
|
"test/connection/test_channel.rb",
|
132
133
|
"test/connection/test_session.rb",
|
133
134
|
"test/known_hosts/github",
|
134
135
|
"test/manual/test_forward.rb",
|
136
|
+
"test/start/test_options.rb",
|
135
137
|
"test/start/test_transport.rb",
|
136
138
|
"test/test_all.rb",
|
137
139
|
"test/test_buffer.rb",
|
@@ -363,6 +363,44 @@ module Connection
|
|
363
363
|
session.process
|
364
364
|
end
|
365
365
|
|
366
|
+
def test_process_should_call_enqueue_message_if_io_select_timed_out
|
367
|
+
timeout = Net::SSH::Connection::Session::DEFAULT_IO_SELECT_TIMEOUT
|
368
|
+
options = { :keepalive => true }
|
369
|
+
expected_packet = P(:byte, Net::SSH::Packet::IGNORE, :string, "keepalive")
|
370
|
+
IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
|
371
|
+
transport.expects(:enqueue_message).with{ |msg| msg.content == expected_packet.content }
|
372
|
+
session(options).process
|
373
|
+
end
|
374
|
+
|
375
|
+
def test_process_should_not_call_enqueue_message_unless_io_select_timed_out
|
376
|
+
timeout = Net::SSH::Connection::Session::DEFAULT_IO_SELECT_TIMEOUT
|
377
|
+
options = { :keepalive => true }
|
378
|
+
IO.stubs(:select).with([socket],[],nil,timeout).returns([[],[],[]])
|
379
|
+
transport.expects(:enqueue_message).never
|
380
|
+
session(options).process
|
381
|
+
end
|
382
|
+
|
383
|
+
def test_process_should_not_call_enqueue_message_unless_keepalive_interval_not_go_on
|
384
|
+
timeout = 10
|
385
|
+
options = { :keepalive => true, :keepalive_interval => timeout }
|
386
|
+
Time.stubs(:now).returns(Time.at(0), Time.at(9), Time.at(timeout))
|
387
|
+
IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
|
388
|
+
transport.expects(:enqueue_message).times(2)
|
389
|
+
3.times { session(options).process }
|
390
|
+
end
|
391
|
+
|
392
|
+
def test_process_should_call_io_select_with_nil_as_last_arg_if_keepalive_disabled
|
393
|
+
IO.expects(:select).with([socket],[],nil,nil).returns([[],[],[]])
|
394
|
+
session.process
|
395
|
+
end
|
396
|
+
|
397
|
+
def test_process_should_call_io_select_with_interval_as_last_arg_if_keepalive_interval_passed
|
398
|
+
timeout = 10
|
399
|
+
options = { :keepalive => true, :keepalive_interval => timeout }
|
400
|
+
IO.expects(:select).with([socket],[],nil,timeout).returns([[],[],[]])
|
401
|
+
session(options).process
|
402
|
+
end
|
403
|
+
|
366
404
|
def test_loop_should_call_process_until_process_returns_false
|
367
405
|
IO.stubs(:select).with([socket],[],nil,nil).returns([[],[],[]])
|
368
406
|
session.expects(:process).with(nil).times(4).returns(true,true,true,false).yields
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'common'
|
2
|
+
require 'net/ssh'
|
3
|
+
|
4
|
+
module NetSSH
|
5
|
+
class TestStartOptions < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
authentication_session = mock('authentication_session')
|
8
|
+
authentication_session.stubs(:authenticate).returns(true)
|
9
|
+
Net::SSH::Authentication::Session.stubs(:new).returns(authentication_session)
|
10
|
+
Net::SSH::Transport::Session.stubs(:new).returns(mock('transport_session'))
|
11
|
+
Net::SSH::Connection::Session.stubs(:new).returns(mock('connection_session'))
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_start_should_accept_keepalive_option
|
15
|
+
assert_nothing_raised do
|
16
|
+
options = { :keepalive => true }
|
17
|
+
Net::SSH.start('localhost', 'testuser', options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_start_should_accept_keepalive_interval_option
|
22
|
+
assert_nothing_raised do
|
23
|
+
options = { :keepalive_interval => 10 }
|
24
|
+
Net::SSH.start('localhost', 'testuser', options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_start_should_accept_send_env_option
|
29
|
+
assert_nothing_raised do
|
30
|
+
options = { :send_env => [ /^LC_.*$/, "LANG" ] }
|
31
|
+
Net::SSH.start('localhost', 'testuser', options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
data/test/test_config.rb
CHANGED
@@ -86,7 +86,8 @@ class TestConfig < Test::Unit::TestCase
|
|
86
86
|
'passwordauthentication' => true,
|
87
87
|
'port' => 1234,
|
88
88
|
'pubkeyauthentication' => true,
|
89
|
-
'rekeylimit' => 1024
|
89
|
+
'rekeylimit' => 1024,
|
90
|
+
'sendenv' => "LC_*"
|
90
91
|
}
|
91
92
|
|
92
93
|
net_ssh = Net::SSH::Config.translate(open_ssh)
|
@@ -103,6 +104,7 @@ class TestConfig < Test::Unit::TestCase
|
|
103
104
|
assert_equal 1234, net_ssh[:port]
|
104
105
|
assert_equal 1024, net_ssh[:rekey_limit]
|
105
106
|
assert_equal "127.0.0.1", net_ssh[:bind_address]
|
107
|
+
assert_equal [/^LC_.*$/], net_ssh[:send_env]
|
106
108
|
end
|
107
109
|
|
108
110
|
def test_load_with_plus_sign_hosts
|
@@ -134,7 +136,13 @@ class TestConfig < Test::Unit::TestCase
|
|
134
136
|
net_ssh = Net::SSH::Config.translate(config)
|
135
137
|
assert_equal 'prefix.1234.sufix', net_ssh[:host_name]
|
136
138
|
end
|
137
|
-
|
139
|
+
|
140
|
+
def test_load_with_send_env
|
141
|
+
config = Net::SSH::Config.load(config(:send_env), "1234")
|
142
|
+
net_ssh = Net::SSH::Config.translate(config)
|
143
|
+
assert_equal [/^GIT_.*$/, /^LANG$/, /^LC_.*$/], net_ssh[:send_env]
|
144
|
+
end
|
145
|
+
|
138
146
|
private
|
139
147
|
|
140
148
|
def config(name)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-ssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-09-11 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: test-unit
|
@@ -163,12 +163,14 @@ files:
|
|
163
163
|
- test/configs/multihost
|
164
164
|
- test/configs/nohost
|
165
165
|
- test/configs/numeric_host
|
166
|
+
- test/configs/send_env
|
166
167
|
- test/configs/substitutes
|
167
168
|
- test/configs/wild_cards
|
168
169
|
- test/connection/test_channel.rb
|
169
170
|
- test/connection/test_session.rb
|
170
171
|
- test/known_hosts/github
|
171
172
|
- test/manual/test_forward.rb
|
173
|
+
- test/start/test_options.rb
|
172
174
|
- test/start/test_transport.rb
|
173
175
|
- test/test_all.rb
|
174
176
|
- test/test_buffer.rb
|