net-ssh 2.0.20 → 2.0.21

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.
@@ -1,4 +1,18 @@
1
1
 
2
+
3
+ === 2.0.21 / 20 Mar 2010
4
+
5
+ * Fix for "IdentifyFile" in ~/.ssh/config does not work if no "Host" statement is given (http://net-ssh.lighthouseapp.com/projects/36253/tickets/9-identifyfile-in-sshconfig-does-not-work-if-no-host-statement-is-given#ticket-9-5) [xbaldauf, Delano Mandelbaum]
6
+
7
+ * Fix for client closes a forwarded connection, but the server is reading, net-ssh terminates with IOError socket closed (http://net-ssh.lighthouseapp.com/projects/36253/tickets/7) [Miklós Fazekas]
8
+
9
+ * Fix for client force closes (RST) a forwarded connection, but server is reading, net-ssh terminates with exception [Miklós Fazekas]
10
+
11
+ * Fix for server closes the sending side, the on_eof is not handled. [Miklós Fazekas]
12
+
13
+ * Removed Hanna dependency in Rakefile [Delano Mandelbaum]
14
+
15
+
2
16
  === 2.0.20 / 10 Feb 2010
3
17
 
4
18
  * Support "ProxyCommand none" directive [Andy Lo-A-Foe]
@@ -20,7 +34,9 @@
20
34
  === 2.0.16 / 28 Nov 2009
21
35
 
22
36
  * Fix for "multiple hosts are separated by whitespace" [Akinori MUSHA]
37
+
23
38
  * Add support for the ProxyCommand directive [Akinori MUSHA]
39
+
24
40
  * Switched from #recv(1) to #readpartial in lib/net/ssh/transport/server_version.rb, so that closed sockets are recognized [Alex Peuchert]
25
41
 
26
42
 
data/Rakefile CHANGED
@@ -1,10 +1,16 @@
1
1
  require 'rubygems'
2
2
  require 'rake/clean'
3
3
  require 'rake/gempackagetask'
4
- require 'hanna/rdoctask'
5
4
  require 'fileutils'
6
5
  include FileUtils
7
-
6
+
7
+ begin
8
+ require 'hanna/rdoctask'
9
+ rescue LoadError
10
+ require 'rake/rdoctask'
11
+ end
12
+
13
+
8
14
  task :default => :package
9
15
 
10
16
  # CONFIG =============================================================
@@ -147,4 +147,52 @@ module Net; module SSH
147
147
  end
148
148
  end
149
149
 
150
+
151
+
152
+ # Fixes for two issues by Miklós Fazekas:
153
+ #
154
+ # * if client closes a forwarded connection, but the server is
155
+ # reading, net-ssh terminates with IOError socket closed.
156
+ # * if client force closes (RST) a forwarded connection, but
157
+ # server is reading, net-ssh terminates with [an exception]
158
+ #
159
+ # See:
160
+ #
161
+ # http://net-ssh.lighthouseapp.com/projects/36253/tickets/7
162
+ # http://github.com/net-ssh/net-ssh/tree/portfwfix
163
+ #
164
+ module ForwardedBufferedIo
165
+ def fill(n=8192)
166
+ begin
167
+ super(n)
168
+ rescue Errno::ECONNRESET => e
169
+ debug { "connection was reset => shallowing exception:#{e}" }
170
+ return 0
171
+ rescue IOError => e
172
+ if e.message =~ /closed/ then
173
+ debug { "connection was reset => shallowing exception:#{e}" }
174
+ return 0
175
+ else
176
+ raise
177
+ end
178
+ end
179
+ end
180
+
181
+ def send_pending
182
+ begin
183
+ super
184
+ rescue Errno::ECONNRESET => e
185
+ debug { "connection was reset => shallowing exception:#{e}" }
186
+ return 0
187
+ rescue IOError => e
188
+ if e.message =~ /closed/ then
189
+ debug { "connection was reset => shallowing exception:#{e}" }
190
+ return 0
191
+ else
192
+ raise
193
+ end
194
+ end
195
+ end
196
+ end
197
+
150
198
  end; end
@@ -55,12 +55,14 @@ module Net; module SSH
55
55
  # ones. Returns a hash containing the OpenSSH options. (See
56
56
  # #translate for how to convert the OpenSSH options into Net::SSH
57
57
  # options.)
58
- def load(file, host, settings={})
59
- file = File.expand_path(file)
58
+ def load(path, host, settings={})
59
+ file = File.expand_path(path)
60
60
  return settings unless File.readable?(file)
61
61
 
62
+ globals = {}
62
63
  matched_host = nil
63
64
  multi_host = []
65
+ seen_host = false
64
66
  IO.foreach(file) do |line|
65
67
  next if line =~ /^\s*(?:#.*)?$/
66
68
 
@@ -75,29 +77,37 @@ module Net; module SSH
75
77
 
76
78
  key.downcase!
77
79
  value = $1 if value =~ /^"(.*)"$/
78
-
80
+
79
81
  value = case value.strip
80
82
  when /^\d+$/ then value.to_i
81
83
  when /^no$/i then false
82
84
  when /^yes$/i then true
83
85
  else value
84
86
  end
85
-
87
+
86
88
  if key == 'host'
87
89
  # Support "Host host1 host2 hostN".
88
90
  # See http://github.com/net-ssh/net-ssh/issues#issue/6
89
91
  multi_host = value.split(/\s+/)
90
92
  matched_host = multi_host.select { |h| host =~ pattern2regex(h) }.first
93
+ seen_host = true
94
+ elsif !seen_host
95
+ if key == 'identityfile'
96
+ (globals[key] ||= []) << value
97
+ else
98
+ globals[key] = value unless settings.key?(key)
99
+ end
91
100
  elsif !matched_host.nil?
92
101
  if key == 'identityfile'
93
- settings[key] ||= []
94
- settings[key] << value
102
+ (settings[key] ||= []) << value
95
103
  else
96
104
  settings[key] = value unless settings.key?(key)
97
105
  end
98
106
  end
99
107
  end
100
108
 
109
+ settings = globals.merge(settings) if globals
110
+
101
111
  return settings
102
112
  end
103
113
 
@@ -193,21 +193,42 @@ module Net; module SSH; module Service
193
193
  end
194
194
 
195
195
  private
196
-
196
+
197
197
  # Perform setup operations that are common to all forwarded channels.
198
198
  # +client+ is a socket, +channel+ is the channel that was just created,
199
199
  # and +type+ is an arbitrary string describing the type of the channel.
200
200
  def prepare_client(client, channel, type)
201
201
  client.extend(Net::SSH::BufferedIo)
202
+ client.extend(Net::SSH::ForwardedBufferedIo)
202
203
  client.logger = logger
203
204
 
204
205
  session.listen_to(client)
205
206
  channel[:socket] = client
206
207
 
207
- channel.on_data do |ch, data|
208
+ channel.on_data do |ch, data|
209
+ debug { "data:#{data.length} on #{type} forwarded channel" }
208
210
  ch[:socket].enqueue(data)
209
211
  end
210
-
212
+
213
+ # Handles server close on the sending side by Miklós Fazekas
214
+ channel.on_eof do |ch|
215
+ debug { "eof #{type} on #{type} forwarded channel" }
216
+ begin
217
+ ch[:socket].send_pending
218
+ ch[:socket].shutdown Socket::SHUT_WR
219
+ rescue IOError => e
220
+ if e.message =~ /closed/ then
221
+ debug { "epipe in on_eof => shallowing exception:#{e}" }
222
+ else
223
+ raise
224
+ end
225
+ rescue Errno::EPIPE => e
226
+ debug { "epipe in on_eof => shallowing exception:#{e}" }
227
+ rescue Errno::ENOTCONN => e
228
+ debug { "enotconn in on_eof => shallowing exception:#{e}" }
229
+ end
230
+ end
231
+
211
232
  channel.on_close do |ch|
212
233
  debug { "closing #{type} forwarded channel" }
213
234
  ch[:socket].close if !client.closed?
@@ -51,7 +51,7 @@ module Net; module SSH
51
51
  MINOR = 0
52
52
 
53
53
  # The tiny component of this version of the Net::SSH library
54
- TINY = 20
54
+ TINY = 21
55
55
 
56
56
  # The current version of the Net::SSH library as a Version instance
57
57
  CURRENT = new(MAJOR, MINOR, TINY)
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "net-ssh"
3
3
  s.rubyforge_project = 'net-ssh'
4
- s.version = "2.0.20"
4
+ s.version = "2.0.21"
5
5
  s.summary = "Net::SSH: a pure-Ruby implementation of the SSH2 client protocol."
6
6
  s.description = s.summary
7
7
  s.authors = ["Jamis Buck", "Delano Mandelbaum"]
@@ -91,6 +91,7 @@
91
91
  setup.rb
92
92
  support/arcfour_check.rb
93
93
  support/ssh_tunnel_bug.rb
94
+ test/README.txt
94
95
  test/authentication/methods/common.rb
95
96
  test/authentication/methods/test_abstract.rb
96
97
  test/authentication/methods/test_hostbased.rb
@@ -105,9 +106,11 @@
105
106
  test/configs/exact_match
106
107
  test/configs/host_plus
107
108
  test/configs/multihost
109
+ test/configs/nohost
108
110
  test/configs/wild_cards
109
111
  test/connection/test_channel.rb
110
112
  test/connection/test_session.rb
113
+ test/manual/test_forward.rb
111
114
  test/test_all.rb
112
115
  test/test_buffer.rb
113
116
  test/test_buffered_io.rb
@@ -0,0 +1,42 @@
1
+ 2010-03-16
2
+
3
+ RUNNING TESTS
4
+
5
+ Run the test suite from the net-ssh directory with the following command:
6
+
7
+ ruby -Ilib -Itest -rrubygems test/test_all.rb
8
+
9
+ Run a single test file like this:
10
+
11
+ ruby -Ilib -Itest -rrubygems test/transport/test_server_version.rb
12
+
13
+
14
+ EXPECTED RESULTS
15
+
16
+ * Ruby 1.8: all tests pass
17
+
18
+ * Ruby 1.9: all tests pass
19
+
20
+ * JRuby 1.4: 96% tests pass (242 tests, 554 assertions, 0 failures, 8 errors)
21
+
22
+
23
+ PORT FORWARDING TESTS
24
+
25
+ ruby -Ilib -Itest -rrubygems test/manual/test_forward.rb
26
+
27
+ test_forward.rb must be run separately from the test suite because
28
+ it requires authorizing your public SSH keys on you localhost.
29
+
30
+ If you already have keys you can do this:
31
+
32
+ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
33
+
34
+ If you don't have keys see:
35
+
36
+ http://kimmo.suominen.com/docs/ssh/#ssh-keygen
37
+
38
+ You should now be able to login to your localhost with out
39
+ bring prompted for a password:
40
+
41
+ ssh localhost
42
+
@@ -0,0 +1,19 @@
1
+
2
+ IdentityFile ~/.ssh/id_dsa
3
+ IdentityFile ~/.ssh/id_rsa
4
+ Port 1980
5
+
6
+ Host test.host
7
+ Port 1985
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
@@ -0,0 +1,185 @@
1
+ # $ ruby -Ilib -Itest -rrubygems test/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 'common'
18
+ require 'net/ssh/buffer'
19
+ require 'net/ssh'
20
+ require 'timeout'
21
+
22
+ class TestForward < Test::Unit::TestCase
23
+
24
+ def localhost
25
+ 'localhost'
26
+ end
27
+
28
+ def ssh_start_params
29
+ [localhost ,ENV['USER']] #:verbose => :debug
30
+ end
31
+
32
+ def find_free_port
33
+ server = TCPServer.open(0)
34
+ server.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR,true)
35
+ port = server.addr[1]
36
+ server.close
37
+ port
38
+ end
39
+
40
+ def start_server_sending_lot_of_data(exceptions)
41
+ server = TCPServer.open(0)
42
+ Thread.start do
43
+ loop do
44
+ Thread.start(server.accept) do |client|
45
+ begin
46
+ 10000.times do |i|
47
+ client.puts "item#{i}"
48
+ end
49
+ client.close
50
+ rescue
51
+ exceptions << $!
52
+ raise
53
+ end
54
+ end
55
+ end
56
+ end
57
+ return server
58
+ end
59
+
60
+ def start_server_closing_soon(exceptions=nil)
61
+ server = TCPServer.open(0)
62
+ Thread.start do
63
+ loop do
64
+ Thread.start(server.accept) do |client|
65
+ begin
66
+ client.recv(1024)
67
+ client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii"))
68
+ client.close
69
+ rescue
70
+ exceptions << $!
71
+ raise
72
+ end
73
+ end
74
+ end
75
+ end
76
+ return server
77
+ end
78
+
79
+ def test_loop_should_not_abort_when_local_side_of_forward_is_closed
80
+ session = Net::SSH.start(*ssh_start_params)
81
+ server_exc = Queue.new
82
+ server = start_server_sending_lot_of_data(server_exc)
83
+ remote_port = server.addr[1]
84
+ local_port = find_free_port
85
+ session.forward.local(local_port, localhost, remote_port)
86
+ client_done = Queue.new
87
+ Thread.start do
88
+ begin
89
+ client = TCPSocket.new(localhost, local_port)
90
+ client.recv(1024)
91
+ client.close
92
+ sleep(0.2)
93
+ ensure
94
+ client_done << true
95
+ end
96
+ end
97
+ session.loop(0.1) { client_done.empty? }
98
+ assert_equal "Broken pipe", "#{server_exc.pop}" unless server_exc.empty?
99
+ end
100
+
101
+ def test_loop_should_not_abort_when_local_side_of_forward_is_reset
102
+ session = Net::SSH.start(*ssh_start_params)
103
+ server_exc = Queue.new
104
+ server = start_server_sending_lot_of_data(server_exc)
105
+ remote_port = server.addr[1]
106
+ local_port = find_free_port
107
+ session.forward.local(local_port, localhost, remote_port)
108
+ client_done = Queue.new
109
+ Thread.start do
110
+ begin
111
+ client = TCPSocket.new(localhost, local_port)
112
+ client.recv(1024)
113
+ client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii"))
114
+ client.close
115
+ sleep(0.1)
116
+ ensure
117
+ client_done << true
118
+ end
119
+ end
120
+ session.loop(0.1) { client_done.empty? }
121
+ assert_equal "Broken pipe", "#{server_exc.pop}" unless server_exc.empty?
122
+ end
123
+
124
+ def test_loop_should_not_abort_when_server_side_of_forward_is_closed
125
+ session = Net::SSH.start(*ssh_start_params)
126
+ server = start_server_closing_soon
127
+ remote_port = server.addr[1]
128
+ local_port = find_free_port
129
+ session.forward.local(local_port, localhost, remote_port)
130
+ client_done = Queue.new
131
+ Thread.start do
132
+ begin
133
+ client = TCPSocket.new(localhost, local_port)
134
+ 1.times do |i|
135
+ client.puts "item#{i}"
136
+ end
137
+ client.close
138
+ sleep(0.1)
139
+ ensure
140
+ client_done << true
141
+ end
142
+ end
143
+ session.loop(0.1) { client_done.empty? }
144
+ end
145
+
146
+ def start_server
147
+ server = TCPServer.open(0)
148
+ Thread.start do
149
+ loop do
150
+ Thread.start(server.accept) do |client|
151
+ yield(client)
152
+ end
153
+ end
154
+ end
155
+ return server
156
+ end
157
+
158
+ def test_server_eof_should_be_handled
159
+ session = Net::SSH.start(*ssh_start_params)
160
+ server = start_server do |client|
161
+ client.write "This is a small message!"
162
+ client.close
163
+ end
164
+ client_done = Queue.new
165
+ client_exception = Queue.new
166
+ client_data = Queue.new
167
+ remote_port = server.addr[1]
168
+ local_port = find_free_port
169
+ session.forward.local(local_port, localhost, remote_port)
170
+ Thread.start do
171
+ begin
172
+ client = TCPSocket.new(localhost, local_port)
173
+ data = client.read(4096)
174
+ client.close
175
+ client_done << data
176
+ rescue
177
+ client_done << $!
178
+ end
179
+ end
180
+ timeout(5) do
181
+ session.loop(0.1) { client_done.empty? }
182
+ assert_equal "This is a small message!", client_done.pop
183
+ end
184
+ end
185
+ end
@@ -2,6 +2,7 @@
2
2
  # $ ruby -Ilib -Itest -rrubygems test/transport/test_server_version.rb
3
3
  Dir.chdir(File.dirname(__FILE__)) do
4
4
  test_files = Dir['**/test_*.rb']
5
+ test_files = test_files.reject { |f| f =~ /^manual/ }
5
6
  test_files = test_files.select { |f| f =~ Regexp.new(ENV['ONLY']) } if ENV['ONLY']
6
7
  test_files = test_files.reject { |f| f =~ Regexp.new(ENV['EXCEPT']) } if ENV['EXCEPT']
7
8
  test_files.each { |file| require(file) }
@@ -38,6 +38,12 @@ class TestConfig < Test::Unit::TestCase
38
38
  assert !config.key?(:rekey_limit)
39
39
  end
40
40
 
41
+ def test_load_with_no_host
42
+ config = Net::SSH::Config.load(config(:nohost), "test.host")
43
+ assert_equal %w(~/.ssh/id_dsa ~/.ssh/id_rsa), config['identityfile']
44
+ assert_equal 1985, config['port']
45
+ end
46
+
41
47
  def test_load_with_multiple_hosts
42
48
  config = Net::SSH::Config.load(config(:multihost), "test.host")
43
49
  assert config['compression']
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.0.20
4
+ version: 2.0.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamis Buck
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2010-02-10 00:00:00 -05:00
13
+ date: 2010-03-20 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -99,6 +99,7 @@ files:
99
99
  - setup.rb
100
100
  - support/arcfour_check.rb
101
101
  - support/ssh_tunnel_bug.rb
102
+ - test/README.txt
102
103
  - test/authentication/methods/common.rb
103
104
  - test/authentication/methods/test_abstract.rb
104
105
  - test/authentication/methods/test_hostbased.rb
@@ -113,9 +114,11 @@ files:
113
114
  - test/configs/exact_match
114
115
  - test/configs/host_plus
115
116
  - test/configs/multihost
117
+ - test/configs/nohost
116
118
  - test/configs/wild_cards
117
119
  - test/connection/test_channel.rb
118
120
  - test/connection/test_session.rb
121
+ - test/manual/test_forward.rb
119
122
  - test/test_all.rb
120
123
  - test/test_buffer.rb
121
124
  - test/test_buffered_io.rb