net-ssh 6.1.0 → 7.3.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.dockerignore +6 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +94 -0
- data/.github/workflows/rubocop.yml +16 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +12 -1
- data/.rubocop_todo.yml +475 -376
- data/CHANGES.txt +64 -3
- data/DEVELOPMENT.md +23 -0
- data/Dockerfile +29 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +2 -0
- data/Gemfile.noed25519 +2 -0
- data/Gemfile.norbnacl +12 -0
- data/README.md +38 -22
- data/Rakefile +92 -0
- data/SECURITY.md +4 -0
- data/docker-compose.yml +25 -0
- data/lib/net/ssh/authentication/agent.rb +29 -13
- data/lib/net/ssh/authentication/certificate.rb +14 -11
- data/lib/net/ssh/authentication/constants.rb +0 -1
- data/lib/net/ssh/authentication/ed25519.rb +14 -11
- data/lib/net/ssh/authentication/ed25519_loader.rb +4 -7
- data/lib/net/ssh/authentication/key_manager.rb +65 -36
- data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
- data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +2 -2
- data/lib/net/ssh/authentication/methods/none.rb +6 -9
- data/lib/net/ssh/authentication/methods/password.rb +2 -3
- data/lib/net/ssh/authentication/methods/publickey.rb +57 -17
- data/lib/net/ssh/authentication/pageant.rb +97 -97
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +3 -3
- data/lib/net/ssh/authentication/session.rb +25 -17
- data/lib/net/ssh/buffer.rb +71 -51
- data/lib/net/ssh/buffered_io.rb +25 -26
- data/lib/net/ssh/config.rb +33 -20
- data/lib/net/ssh/connection/channel.rb +84 -82
- data/lib/net/ssh/connection/constants.rb +0 -4
- data/lib/net/ssh/connection/event_loop.rb +30 -24
- data/lib/net/ssh/connection/keepalive.rb +12 -12
- data/lib/net/ssh/connection/session.rb +109 -108
- data/lib/net/ssh/connection/term.rb +56 -58
- data/lib/net/ssh/errors.rb +12 -12
- data/lib/net/ssh/key_factory.rb +7 -8
- data/lib/net/ssh/known_hosts.rb +86 -18
- data/lib/net/ssh/loggable.rb +8 -9
- data/lib/net/ssh/packet.rb +1 -1
- data/lib/net/ssh/prompt.rb +9 -11
- data/lib/net/ssh/proxy/command.rb +1 -1
- data/lib/net/ssh/proxy/errors.rb +2 -4
- data/lib/net/ssh/proxy/http.rb +18 -20
- data/lib/net/ssh/proxy/https.rb +8 -10
- data/lib/net/ssh/proxy/jump.rb +8 -10
- data/lib/net/ssh/proxy/socks4.rb +2 -4
- data/lib/net/ssh/proxy/socks5.rb +3 -5
- data/lib/net/ssh/service/forward.rb +7 -7
- data/lib/net/ssh/test/channel.rb +24 -26
- data/lib/net/ssh/test/extensions.rb +35 -35
- data/lib/net/ssh/test/kex.rb +6 -8
- data/lib/net/ssh/test/local_packet.rb +0 -2
- data/lib/net/ssh/test/packet.rb +3 -3
- data/lib/net/ssh/test/remote_packet.rb +6 -8
- data/lib/net/ssh/test/script.rb +25 -27
- data/lib/net/ssh/test/socket.rb +12 -15
- data/lib/net/ssh/test.rb +4 -5
- data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
- data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
- data/lib/net/ssh/transport/algorithms.rb +51 -19
- data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
- data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
- data/lib/net/ssh/transport/cipher_factory.rb +56 -29
- data/lib/net/ssh/transport/constants.rb +3 -3
- data/lib/net/ssh/transport/ctr.rb +7 -7
- data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +20 -5
- data/lib/net/ssh/transport/hmac/md5.rb +0 -2
- data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/none.rb +0 -2
- data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
- data/lib/net/ssh/transport/hmac.rb +12 -12
- data/lib/net/ssh/transport/identity_cipher.rb +19 -13
- data/lib/net/ssh/transport/kex/abstract.rb +12 -5
- data/lib/net/ssh/transport/kex/abstract5656.rb +1 -1
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +2 -1
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +4 -4
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +21 -21
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -2
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
- data/lib/net/ssh/transport/kex.rb +8 -6
- data/lib/net/ssh/transport/key_expander.rb +7 -8
- data/lib/net/ssh/transport/openssl.rb +51 -26
- data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
- data/lib/net/ssh/transport/packet_stream.rb +46 -26
- data/lib/net/ssh/transport/server_version.rb +17 -16
- data/lib/net/ssh/transport/session.rb +9 -7
- data/lib/net/ssh/transport/state.rb +44 -44
- data/lib/net/ssh/verifiers/accept_new.rb +0 -2
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
- data/lib/net/ssh/verifiers/always.rb +6 -4
- data/lib/net/ssh/verifiers/never.rb +0 -2
- data/lib/net/ssh/version.rb +2 -2
- data/lib/net/ssh.rb +15 -8
- data/net-ssh-public_cert.pem +19 -18
- data/net-ssh.gemspec +7 -4
- data/support/ssh_tunnel_bug.rb +3 -3
- data.tar.gz.sig +0 -0
- metadata +76 -29
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -52
|
@@ -5,7 +5,6 @@ require 'net/ssh/connection/term'
|
|
|
5
5
|
module Net
|
|
6
6
|
module SSH
|
|
7
7
|
module Connection
|
|
8
|
-
|
|
9
8
|
# The channel abstraction. Multiple "channels" can be multiplexed onto a
|
|
10
9
|
# single SSH channel, each operating independently and seemingly in parallel.
|
|
11
10
|
# This class represents a single such channel. Most operations performed
|
|
@@ -55,55 +54,55 @@ module Net
|
|
|
55
54
|
class Channel
|
|
56
55
|
include Loggable
|
|
57
56
|
include Constants
|
|
58
|
-
|
|
57
|
+
|
|
59
58
|
# The local id for this channel, assigned by the Net::SSH::Connection::Session instance.
|
|
60
59
|
attr_reader :local_id
|
|
61
|
-
|
|
60
|
+
|
|
62
61
|
# The remote id for this channel, assigned by the remote host.
|
|
63
62
|
attr_reader :remote_id
|
|
64
|
-
|
|
63
|
+
|
|
65
64
|
# The type of this channel, usually "session".
|
|
66
65
|
attr_reader :type
|
|
67
|
-
|
|
66
|
+
|
|
68
67
|
# The underlying Net::SSH::Connection::Session instance that supports this channel.
|
|
69
68
|
attr_reader :connection
|
|
70
|
-
|
|
69
|
+
|
|
71
70
|
# The maximum packet size that the local host can receive.
|
|
72
71
|
attr_reader :local_maximum_packet_size
|
|
73
|
-
|
|
72
|
+
|
|
74
73
|
# The maximum amount of data that the local end of this channel can
|
|
75
74
|
# receive. This is a total, not per-packet.
|
|
76
75
|
attr_reader :local_maximum_window_size
|
|
77
|
-
|
|
76
|
+
|
|
78
77
|
# The maximum packet size that the remote host can receive.
|
|
79
78
|
attr_reader :remote_maximum_packet_size
|
|
80
|
-
|
|
79
|
+
|
|
81
80
|
# The maximum amount of data that the remote end of this channel can
|
|
82
81
|
# receive. This is a total, not per-packet.
|
|
83
82
|
attr_reader :remote_maximum_window_size
|
|
84
|
-
|
|
83
|
+
|
|
85
84
|
# This is the remaining window size on the local end of this channel. When
|
|
86
85
|
# this reaches zero, no more data can be received.
|
|
87
86
|
attr_reader :local_window_size
|
|
88
|
-
|
|
87
|
+
|
|
89
88
|
# This is the remaining window size on the remote end of this channel. When
|
|
90
89
|
# this reaches zero, no more data can be sent.
|
|
91
90
|
attr_reader :remote_window_size
|
|
92
|
-
|
|
91
|
+
|
|
93
92
|
# A hash of properties for this channel. These can be used to store state
|
|
94
93
|
# information about this channel. See also #[] and #[]=.
|
|
95
94
|
attr_reader :properties
|
|
96
|
-
|
|
95
|
+
|
|
97
96
|
# The output buffer for this channel. Data written to the channel is
|
|
98
97
|
# enqueued here, to be written as CHANNEL_DATA packets during each pass of
|
|
99
98
|
# the event loop. See Connection::Session#process and #enqueue_pending_output.
|
|
100
|
-
attr_reader :output
|
|
101
|
-
|
|
99
|
+
attr_reader :output # :nodoc:
|
|
100
|
+
|
|
102
101
|
# The list of pending requests. Each time a request is sent which requires
|
|
103
102
|
# a reply, the corresponding callback is pushed onto this queue. As responses
|
|
104
103
|
# arrive, they are shifted off the front and handled.
|
|
105
|
-
attr_reader :pending_requests
|
|
106
|
-
|
|
104
|
+
attr_reader :pending_requests # :nodoc:
|
|
105
|
+
|
|
107
106
|
# Instantiates a new channel on the given connection, of the given type,
|
|
108
107
|
# and with the given id. If a block is given, it will be remembered until
|
|
109
108
|
# the channel is confirmed open by the server, and will be invoked at
|
|
@@ -112,36 +111,36 @@ module Net
|
|
|
112
111
|
# This also sets the default maximum packet size and maximum window size.
|
|
113
112
|
def initialize(connection, type, local_id, max_pkt_size = 0x8000, max_win_size = 0x20000, &on_confirm_open)
|
|
114
113
|
self.logger = connection.logger
|
|
115
|
-
|
|
114
|
+
|
|
116
115
|
@connection = connection
|
|
117
116
|
@type = type
|
|
118
117
|
@local_id = local_id
|
|
119
|
-
|
|
118
|
+
|
|
120
119
|
@local_maximum_packet_size = max_pkt_size
|
|
121
120
|
@local_window_size = @local_maximum_window_size = max_win_size
|
|
122
|
-
|
|
121
|
+
|
|
123
122
|
@on_confirm_open = on_confirm_open
|
|
124
|
-
|
|
123
|
+
|
|
125
124
|
@output = Buffer.new
|
|
126
|
-
|
|
125
|
+
|
|
127
126
|
@properties = {}
|
|
128
|
-
|
|
127
|
+
|
|
129
128
|
@pending_requests = []
|
|
130
129
|
@on_open_failed = @on_data = @on_extended_data = @on_process = @on_close = @on_eof = nil
|
|
131
130
|
@on_request = {}
|
|
132
131
|
@closing = @eof = @sent_eof = @local_closed = @remote_closed = false
|
|
133
132
|
end
|
|
134
|
-
|
|
133
|
+
|
|
135
134
|
# A shortcut for accessing properties of the channel (see #properties).
|
|
136
135
|
def [](name)
|
|
137
136
|
@properties[name]
|
|
138
137
|
end
|
|
139
|
-
|
|
138
|
+
|
|
140
139
|
# A shortcut for setting properties of the channel (see #properties).
|
|
141
140
|
def []=(name, value)
|
|
142
141
|
@properties[name] = value
|
|
143
142
|
end
|
|
144
|
-
|
|
143
|
+
|
|
145
144
|
# Syntactic sugar for executing a command. Sends a channel request asking
|
|
146
145
|
# that the given command be invoked. If the block is given, it will be
|
|
147
146
|
# called when the server responds. The first parameter will be the
|
|
@@ -161,7 +160,7 @@ module Net
|
|
|
161
160
|
def exec(command, &block)
|
|
162
161
|
send_channel_request("exec", :string, command, &block)
|
|
163
162
|
end
|
|
164
|
-
|
|
163
|
+
|
|
165
164
|
# Syntactic sugar for requesting that a subsystem be started. Subsystems
|
|
166
165
|
# are a way for other protocols (like SFTP) to be run, using SSH as
|
|
167
166
|
# the transport. Generally, you'll never need to call this directly unless
|
|
@@ -178,7 +177,7 @@ module Net
|
|
|
178
177
|
def subsystem(subsystem, &block)
|
|
179
178
|
send_channel_request("subsystem", :string, subsystem, &block)
|
|
180
179
|
end
|
|
181
|
-
|
|
180
|
+
|
|
182
181
|
# Syntactic sugar for setting an environment variable in the remote
|
|
183
182
|
# process' environment. Note that for security reasons, the server may
|
|
184
183
|
# refuse to set certain environment variables, or all, at the server's
|
|
@@ -190,7 +189,7 @@ module Net
|
|
|
190
189
|
def env(variable_name, variable_value, &block)
|
|
191
190
|
send_channel_request("env", :string, variable_name, :string, variable_value, &block)
|
|
192
191
|
end
|
|
193
|
-
|
|
192
|
+
|
|
194
193
|
# A hash of the valid PTY options (see #request_pty).
|
|
195
194
|
VALID_PTY_OPTIONS = { term: "xterm",
|
|
196
195
|
chars_wide: 80,
|
|
@@ -198,7 +197,7 @@ module Net
|
|
|
198
197
|
pixels_wide: 640,
|
|
199
198
|
pixels_high: 480,
|
|
200
199
|
modes: {} }
|
|
201
|
-
|
|
200
|
+
|
|
202
201
|
# Requests that a pseudo-tty (or "pty") be made available for this channel.
|
|
203
202
|
# This is useful when you want to invoke and interact with some kind of
|
|
204
203
|
# screen-based program (e.g., vim, or some menuing system).
|
|
@@ -218,24 +217,24 @@ module Net
|
|
|
218
217
|
# puts "could not obtain pty"
|
|
219
218
|
# end
|
|
220
219
|
# end
|
|
221
|
-
def request_pty(opts={}, &block)
|
|
220
|
+
def request_pty(opts = {}, &block)
|
|
222
221
|
extra = opts.keys - VALID_PTY_OPTIONS.keys
|
|
223
222
|
raise ArgumentError, "invalid option(s) to request_pty: #{extra.inspect}" if extra.any?
|
|
224
|
-
|
|
223
|
+
|
|
225
224
|
opts = VALID_PTY_OPTIONS.merge(opts)
|
|
226
|
-
|
|
225
|
+
|
|
227
226
|
modes = opts[:modes].inject(Buffer.new) do |memo, (mode, data)|
|
|
228
227
|
memo.write_byte(mode).write_long(data)
|
|
229
228
|
end
|
|
230
229
|
# mark the end of the mode opcode list with a 0 byte
|
|
231
230
|
modes.write_byte(0)
|
|
232
|
-
|
|
231
|
+
|
|
233
232
|
send_channel_request("pty-req", :string, opts[:term],
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
233
|
+
:long, opts[:chars_wide], :long, opts[:chars_high],
|
|
234
|
+
:long, opts[:pixels_wide], :long, opts[:pixels_high],
|
|
235
|
+
:string, modes.to_s, &block)
|
|
237
236
|
end
|
|
238
|
-
|
|
237
|
+
|
|
239
238
|
# Sends data to the channel's remote endpoint. This usually has the
|
|
240
239
|
# effect of sending the given string to the remote process' stdin stream.
|
|
241
240
|
# Note that it does not immediately send the data across the channel,
|
|
@@ -251,9 +250,10 @@ module Net
|
|
|
251
250
|
# channel.send_data("the password\n")
|
|
252
251
|
def send_data(data)
|
|
253
252
|
raise EOFError, "cannot send data if channel has declared eof" if eof?
|
|
253
|
+
|
|
254
254
|
output.append(data.to_s)
|
|
255
255
|
end
|
|
256
|
-
|
|
256
|
+
|
|
257
257
|
# Returns true if the channel exists in the channel list of the session,
|
|
258
258
|
# and false otherwise. This can be used to determine whether a channel has
|
|
259
259
|
# been closed or not.
|
|
@@ -262,7 +262,7 @@ module Net
|
|
|
262
262
|
def active?
|
|
263
263
|
connection.channels.key?(local_id)
|
|
264
264
|
end
|
|
265
|
-
|
|
265
|
+
|
|
266
266
|
# Runs the SSH event loop until the channel is no longer active. This is
|
|
267
267
|
# handy for blocking while you wait for some channel to finish.
|
|
268
268
|
#
|
|
@@ -271,7 +271,7 @@ module Net
|
|
|
271
271
|
def wait
|
|
272
272
|
connection.loop { active? }
|
|
273
273
|
end
|
|
274
|
-
|
|
274
|
+
|
|
275
275
|
# True if close() has been called; NOTE: if the channel has data waiting to
|
|
276
276
|
# be sent then the channel will close after all the data is sent. See
|
|
277
277
|
# closed?() to determine if we have actually sent CHANNEL_CLOSE to server.
|
|
@@ -280,61 +280,63 @@ module Net
|
|
|
280
280
|
def closing?
|
|
281
281
|
@closing
|
|
282
282
|
end
|
|
283
|
-
|
|
283
|
+
|
|
284
284
|
# True if we have sent CHANNEL_CLOSE to the remote server.
|
|
285
285
|
def local_closed?
|
|
286
286
|
@local_closed
|
|
287
287
|
end
|
|
288
|
-
|
|
288
|
+
|
|
289
289
|
def remote_closed?
|
|
290
290
|
@remote_closed
|
|
291
291
|
end
|
|
292
|
-
|
|
292
|
+
|
|
293
293
|
def remote_closed!
|
|
294
294
|
@remote_closed = true
|
|
295
295
|
end
|
|
296
|
-
|
|
296
|
+
|
|
297
297
|
# Requests that the channel be closed. It only marks the channel to be closed
|
|
298
298
|
# the CHANNEL_CLOSE message will be sent from event loop
|
|
299
299
|
def close
|
|
300
300
|
return if @closing
|
|
301
|
+
|
|
301
302
|
@closing = true
|
|
302
303
|
end
|
|
303
|
-
|
|
304
|
+
|
|
304
305
|
# Returns true if the local end of the channel has declared that no more
|
|
305
306
|
# data is forthcoming (see #eof!). Trying to send data via #send_data when
|
|
306
307
|
# this is true will result in an exception being raised.
|
|
307
308
|
def eof?
|
|
308
309
|
@eof
|
|
309
310
|
end
|
|
310
|
-
|
|
311
|
+
|
|
311
312
|
# Tells the remote end of the channel that no more data is forthcoming
|
|
312
313
|
# from this end of the channel. The remote end may still send data.
|
|
313
314
|
# The CHANNEL_EOF packet will be sent once the output buffer is empty.
|
|
314
315
|
def eof!
|
|
315
316
|
return if eof?
|
|
317
|
+
|
|
316
318
|
@eof = true
|
|
317
319
|
end
|
|
318
|
-
|
|
320
|
+
|
|
319
321
|
# If an #on_process handler has been set up, this will cause it to be
|
|
320
322
|
# invoked (passing the channel itself as an argument). It also causes all
|
|
321
323
|
# pending output to be enqueued as CHANNEL_DATA packets (see #enqueue_pending_output).
|
|
322
324
|
def process
|
|
323
325
|
@on_process.call(self) if @on_process
|
|
324
326
|
enqueue_pending_output
|
|
325
|
-
|
|
327
|
+
|
|
326
328
|
if @eof and not @sent_eof and output.empty? and remote_id and not @local_closed
|
|
327
329
|
connection.send_message(Buffer.from(:byte, CHANNEL_EOF, :long, remote_id))
|
|
328
330
|
@sent_eof = true
|
|
329
331
|
end
|
|
330
|
-
|
|
332
|
+
|
|
331
333
|
if @closing and not @local_closed and output.empty? and remote_id
|
|
332
334
|
connection.send_message(Buffer.from(:byte, CHANNEL_CLOSE, :long, remote_id))
|
|
333
335
|
@local_closed = true
|
|
334
336
|
connection.cleanup_channel(self)
|
|
335
337
|
end
|
|
336
338
|
end
|
|
337
|
-
|
|
339
|
+
|
|
338
340
|
# Registers a callback to be invoked when data packets are received by the
|
|
339
341
|
# channel. The callback is called with the channel as the first argument,
|
|
340
342
|
# and the data as the second.
|
|
@@ -349,7 +351,7 @@ module Net
|
|
|
349
351
|
old, @on_data = @on_data, block
|
|
350
352
|
old
|
|
351
353
|
end
|
|
352
|
-
|
|
354
|
+
|
|
353
355
|
# Registers a callback to be invoked when extended data packets are received
|
|
354
356
|
# by the channel. The callback is called with the channel as the first
|
|
355
357
|
# argument, the data type (as an integer) as the second, and the data as
|
|
@@ -364,7 +366,7 @@ module Net
|
|
|
364
366
|
old, @on_extended_data = @on_extended_data, block
|
|
365
367
|
old
|
|
366
368
|
end
|
|
367
|
-
|
|
369
|
+
|
|
368
370
|
# Registers a callback to be invoked for each pass of the event loop for
|
|
369
371
|
# this channel. There are no guarantees on timeliness in the event loop,
|
|
370
372
|
# but it will be called roughly once for each packet received by the
|
|
@@ -391,7 +393,7 @@ module Net
|
|
|
391
393
|
old, @on_process = @on_process, block
|
|
392
394
|
old
|
|
393
395
|
end
|
|
394
|
-
|
|
396
|
+
|
|
395
397
|
# Registers a callback to be invoked when the server acknowledges that a
|
|
396
398
|
# channel is closed. This is invoked with the channel as the sole argument.
|
|
397
399
|
#
|
|
@@ -402,7 +404,7 @@ module Net
|
|
|
402
404
|
old, @on_close = @on_close, block
|
|
403
405
|
old
|
|
404
406
|
end
|
|
405
|
-
|
|
407
|
+
|
|
406
408
|
# Registers a callback to be invoked when the server indicates that no more
|
|
407
409
|
# data will be sent to the channel (although the channel can still send
|
|
408
410
|
# data to the server). The channel is the sole argument to the callback.
|
|
@@ -414,7 +416,7 @@ module Net
|
|
|
414
416
|
old, @on_eof = @on_eof, block
|
|
415
417
|
old
|
|
416
418
|
end
|
|
417
|
-
|
|
419
|
+
|
|
418
420
|
# Registers a callback to be invoked when the server was unable to open
|
|
419
421
|
# the requested channel. The channel itself will be passed to the block,
|
|
420
422
|
# along with the integer "reason code" for the failure, and a textual
|
|
@@ -429,7 +431,7 @@ module Net
|
|
|
429
431
|
old, @on_open_failed = @on_open_failed, block
|
|
430
432
|
old
|
|
431
433
|
end
|
|
432
|
-
|
|
434
|
+
|
|
433
435
|
# Registers a callback to be invoked when a channel request of the given
|
|
434
436
|
# type is received. The callback will receive the channel as the first
|
|
435
437
|
# argument, and the associated (unparsed) data as the second. The data
|
|
@@ -460,7 +462,7 @@ module Net
|
|
|
460
462
|
old, @on_request[type] = @on_request[type], block
|
|
461
463
|
old
|
|
462
464
|
end
|
|
463
|
-
|
|
465
|
+
|
|
464
466
|
# Sends a new channel request with the given name. The extra +data+
|
|
465
467
|
# parameter must either be empty, or consist of an even number of
|
|
466
468
|
# arguments. See Net::SSH::Buffer.from for a description of their format.
|
|
@@ -486,28 +488,29 @@ module Net
|
|
|
486
488
|
def send_channel_request(request_name, *data, &callback)
|
|
487
489
|
info { "sending channel request #{request_name.inspect}" }
|
|
488
490
|
fail "Channel open not yet confirmed, please call send_channel_request(or exec) from block of open_channel" unless remote_id
|
|
491
|
+
|
|
489
492
|
msg = Buffer.from(:byte, CHANNEL_REQUEST,
|
|
490
|
-
|
|
491
|
-
|
|
493
|
+
:long, remote_id, :string, request_name,
|
|
494
|
+
:bool, !callback.nil?, *data)
|
|
492
495
|
connection.send_message(msg)
|
|
493
496
|
pending_requests << callback if callback
|
|
494
497
|
end
|
|
495
|
-
|
|
498
|
+
|
|
496
499
|
public # these methods are public, but for Net::SSH internal use only
|
|
497
|
-
|
|
500
|
+
|
|
498
501
|
# Enqueues pending output at the connection as CHANNEL_DATA packets. This
|
|
499
502
|
# does nothing if the channel has not yet been confirmed open (see
|
|
500
503
|
# #do_open_confirmation). This is called automatically by #process, which
|
|
501
504
|
# is called from the event loop (Connection::Session#process). You will
|
|
502
505
|
# generally not need to invoke it directly.
|
|
503
|
-
def enqueue_pending_output
|
|
506
|
+
def enqueue_pending_output # :nodoc:
|
|
504
507
|
return unless remote_id
|
|
505
|
-
|
|
508
|
+
|
|
506
509
|
while output.length > 0
|
|
507
510
|
length = output.length
|
|
508
511
|
length = remote_window_size if length > remote_window_size
|
|
509
512
|
length = remote_maximum_packet_size if length > remote_maximum_packet_size
|
|
510
|
-
|
|
513
|
+
|
|
511
514
|
if length > 0
|
|
512
515
|
connection.send_message(Buffer.from(:byte, CHANNEL_DATA, :long, remote_id, :string, output.read(length)))
|
|
513
516
|
output.consume!
|
|
@@ -517,14 +520,14 @@ module Net
|
|
|
517
520
|
end
|
|
518
521
|
end
|
|
519
522
|
end
|
|
520
|
-
|
|
523
|
+
|
|
521
524
|
# Invoked when the server confirms that a channel has been opened.
|
|
522
525
|
# The remote_id is the id of the channel as assigned by the remote host,
|
|
523
526
|
# and max_window and max_packet are the maximum window and maximum
|
|
524
527
|
# packet sizes, respectively. If an open-confirmation callback was
|
|
525
528
|
# given when the channel was created, it is invoked at this time with
|
|
526
529
|
# the channel itself as the sole argument.
|
|
527
|
-
def do_open_confirmation(remote_id, max_window, max_packet)
|
|
530
|
+
def do_open_confirmation(remote_id, max_window, max_packet) # :nodoc:
|
|
528
531
|
@remote_id = remote_id
|
|
529
532
|
@remote_window_size = @remote_maximum_window_size = max_window
|
|
530
533
|
@remote_maximum_packet_size = max_packet
|
|
@@ -533,7 +536,7 @@ module Net
|
|
|
533
536
|
set_remote_env(connection.options[:set_env]) if connection.options[:set_env]
|
|
534
537
|
@on_confirm_open.call(self) if @on_confirm_open
|
|
535
538
|
end
|
|
536
|
-
|
|
539
|
+
|
|
537
540
|
# Invoked when the server failed to open the channel. If an #on_open_failed
|
|
538
541
|
# callback was specified, it will be invoked with the channel, reason code,
|
|
539
542
|
# and description as arguments. Otherwise, a ChannelOpenFailed exception
|
|
@@ -545,16 +548,16 @@ module Net
|
|
|
545
548
|
raise ChannelOpenFailed.new(reason_code, description)
|
|
546
549
|
end
|
|
547
550
|
end
|
|
548
|
-
|
|
551
|
+
|
|
549
552
|
# Invoked when the server sends a CHANNEL_WINDOW_ADJUST packet, and
|
|
550
553
|
# causes the remote window size to be adjusted upwards by the given
|
|
551
554
|
# number of bytes. This has the effect of allowing more data to be sent
|
|
552
555
|
# from the local end to the remote end of the channel.
|
|
553
|
-
def do_window_adjust(bytes)
|
|
556
|
+
def do_window_adjust(bytes) # :nodoc:
|
|
554
557
|
@remote_maximum_window_size += bytes
|
|
555
558
|
@remote_window_size += bytes
|
|
556
559
|
end
|
|
557
|
-
|
|
560
|
+
|
|
558
561
|
# Invoked when the server sends a channel request. If any #on_request
|
|
559
562
|
# callback has been registered for the specific type of this request,
|
|
560
563
|
# it is invoked. If +want_reply+ is true, a packet will be sent of
|
|
@@ -563,32 +566,32 @@ module Net
|
|
|
563
566
|
# CHANNEL_SUCCESS, unless the callback raised ChannelRequestFailed. The
|
|
564
567
|
# callback should accept the channel as the first argument, and the
|
|
565
568
|
# request-specific data as the second.
|
|
566
|
-
def do_request(request, want_reply, data)
|
|
569
|
+
def do_request(request, want_reply, data) # :nodoc:
|
|
567
570
|
result = true
|
|
568
|
-
|
|
571
|
+
|
|
569
572
|
begin
|
|
570
573
|
callback = @on_request[request] or raise ChannelRequestFailed
|
|
571
574
|
callback.call(self, data)
|
|
572
575
|
rescue ChannelRequestFailed
|
|
573
576
|
result = false
|
|
574
577
|
end
|
|
575
|
-
|
|
578
|
+
|
|
576
579
|
if want_reply
|
|
577
580
|
msg = Buffer.from(:byte, result ? CHANNEL_SUCCESS : CHANNEL_FAILURE, :long, remote_id)
|
|
578
581
|
connection.send_message(msg)
|
|
579
582
|
end
|
|
580
583
|
end
|
|
581
|
-
|
|
584
|
+
|
|
582
585
|
# Invokes the #on_data callback when the server sends data to the
|
|
583
586
|
# channel. This will reduce the available window size on the local end,
|
|
584
587
|
# but does not actually throttle requests that come in illegally when
|
|
585
588
|
# the window size is too small. The callback is invoked with the channel
|
|
586
589
|
# as the first argument, and the data as the second.
|
|
587
|
-
def do_data(data)
|
|
590
|
+
def do_data(data) # :nodoc:
|
|
588
591
|
update_local_window_size(data.length)
|
|
589
592
|
@on_data.call(self, data) if @on_data
|
|
590
593
|
end
|
|
591
|
-
|
|
594
|
+
|
|
592
595
|
# Invokes the #on_extended_data callback when the server sends
|
|
593
596
|
# extended data to the channel. This will reduce the available window
|
|
594
597
|
# size on the local end. The callback is invoked with the channel,
|
|
@@ -597,20 +600,20 @@ module Net
|
|
|
597
600
|
update_local_window_size(data.length)
|
|
598
601
|
@on_extended_data.call(self, type, data) if @on_extended_data
|
|
599
602
|
end
|
|
600
|
-
|
|
603
|
+
|
|
601
604
|
# Invokes the #on_eof callback when the server indicates that no
|
|
602
605
|
# further data is forthcoming. The callback is invoked with the channel
|
|
603
606
|
# as the argument.
|
|
604
607
|
def do_eof
|
|
605
608
|
@on_eof.call(self) if @on_eof
|
|
606
609
|
end
|
|
607
|
-
|
|
610
|
+
|
|
608
611
|
# Invokes the #on_close callback when the server closes a channel.
|
|
609
612
|
# The channel is the only argument.
|
|
610
613
|
def do_close
|
|
611
614
|
@on_close.call(self) if @on_close
|
|
612
615
|
end
|
|
613
|
-
|
|
616
|
+
|
|
614
617
|
# Invokes the next pending request callback with +false+ as the second
|
|
615
618
|
# argument.
|
|
616
619
|
def do_failure
|
|
@@ -620,7 +623,7 @@ module Net
|
|
|
620
623
|
error { "channel failure received with no pending request to handle it (bug?)" }
|
|
621
624
|
end
|
|
622
625
|
end
|
|
623
|
-
|
|
626
|
+
|
|
624
627
|
# Invokes the next pending request callback with +true+ as the second
|
|
625
628
|
# argument.
|
|
626
629
|
def do_success
|
|
@@ -686,7 +689,6 @@ module Net
|
|
|
686
689
|
env.each { |key, value| self.env(key, value) }
|
|
687
690
|
end
|
|
688
691
|
end
|
|
689
|
-
|
|
690
692
|
end
|
|
691
693
|
end
|
|
692
694
|
end
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
module Net
|
|
2
2
|
module SSH
|
|
3
3
|
module Connection
|
|
4
|
-
|
|
5
4
|
# Definitions of constants that are specific to the connection layer of the
|
|
6
5
|
# SSH protocol.
|
|
7
6
|
module Constants
|
|
8
|
-
|
|
9
7
|
#--
|
|
10
8
|
# Connection protocol generic messages
|
|
11
9
|
#++
|
|
@@ -29,9 +27,7 @@ module Net
|
|
|
29
27
|
CHANNEL_REQUEST = 98
|
|
30
28
|
CHANNEL_SUCCESS = 99
|
|
31
29
|
CHANNEL_FAILURE = 100
|
|
32
|
-
|
|
33
30
|
end
|
|
34
|
-
|
|
35
31
|
end
|
|
36
32
|
end
|
|
37
33
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'net/ssh/loggable'
|
|
2
2
|
|
|
3
|
-
module Net
|
|
4
|
-
module SSH
|
|
3
|
+
module Net
|
|
4
|
+
module SSH
|
|
5
5
|
module Connection
|
|
6
6
|
# EventLoop can be shared across multiple sessions
|
|
7
7
|
#
|
|
@@ -11,81 +11,84 @@ module Net
|
|
|
11
11
|
# and we don't pass session.
|
|
12
12
|
class EventLoop
|
|
13
13
|
include Loggable
|
|
14
|
-
|
|
15
|
-
def initialize(logger=nil)
|
|
14
|
+
|
|
15
|
+
def initialize(logger = nil)
|
|
16
16
|
self.logger = logger
|
|
17
17
|
@sessions = []
|
|
18
18
|
end
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
def register(session)
|
|
21
21
|
@sessions << session
|
|
22
22
|
end
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
# process until timeout
|
|
25
25
|
# if a block is given a session will be removed from loop
|
|
26
26
|
# if block returns false for that session
|
|
27
27
|
def process(wait = nil, &block)
|
|
28
28
|
return false unless ev_preprocess(&block)
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
ev_select_and_postprocess(wait)
|
|
31
31
|
end
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
# process the event loop but only for the sepcified session
|
|
34
34
|
def process_only(session, wait = nil)
|
|
35
35
|
orig_sessions = @sessions
|
|
36
36
|
begin
|
|
37
37
|
@sessions = [session]
|
|
38
38
|
return false unless ev_preprocess
|
|
39
|
+
|
|
39
40
|
ev_select_and_postprocess(wait)
|
|
40
41
|
ensure
|
|
41
42
|
@sessions = orig_sessions
|
|
42
43
|
end
|
|
43
44
|
end
|
|
44
|
-
|
|
45
|
+
|
|
45
46
|
# Call preprocess on each session. If block given and that
|
|
46
47
|
# block retuns false then we exit the processing
|
|
47
48
|
def ev_preprocess(&block)
|
|
48
49
|
return false if block_given? && !yield(self)
|
|
50
|
+
|
|
49
51
|
@sessions.each(&:ev_preprocess)
|
|
50
52
|
return false if block_given? && !yield(self)
|
|
53
|
+
|
|
51
54
|
return true
|
|
52
55
|
end
|
|
53
|
-
|
|
56
|
+
|
|
54
57
|
def ev_select_and_postprocess(wait)
|
|
55
58
|
owners = {}
|
|
56
59
|
r = []
|
|
57
60
|
w = []
|
|
58
61
|
minwait = nil
|
|
59
62
|
@sessions.each do |session|
|
|
60
|
-
sr,sw,actwait = session.ev_do_calculate_rw_wait(wait)
|
|
63
|
+
sr, sw, actwait = session.ev_do_calculate_rw_wait(wait)
|
|
61
64
|
minwait = actwait if actwait && (minwait.nil? || actwait < minwait)
|
|
62
65
|
r.push(*sr)
|
|
63
66
|
w.push(*sw)
|
|
64
67
|
sr.each { |ri| owners[ri] = session }
|
|
65
68
|
sw.each { |wi| owners[wi] = session }
|
|
66
69
|
end
|
|
67
|
-
|
|
70
|
+
|
|
68
71
|
readers, writers, = IO.select(r, w, nil, minwait)
|
|
69
|
-
|
|
72
|
+
|
|
70
73
|
fired_sessions = {}
|
|
71
|
-
|
|
74
|
+
|
|
72
75
|
if readers
|
|
73
76
|
readers.each do |reader|
|
|
74
77
|
session = owners[reader]
|
|
75
|
-
(fired_sessions[session] ||= { r: [],w: [] })[:r] << reader
|
|
78
|
+
(fired_sessions[session] ||= { r: [], w: [] })[:r] << reader
|
|
76
79
|
end
|
|
77
80
|
end
|
|
78
81
|
if writers
|
|
79
82
|
writers.each do |writer|
|
|
80
83
|
session = owners[writer]
|
|
81
|
-
(fired_sessions[session] ||= { r: [],w: [] })[:w] << writer
|
|
84
|
+
(fired_sessions[session] ||= { r: [], w: [] })[:w] << writer
|
|
82
85
|
end
|
|
83
86
|
end
|
|
84
|
-
|
|
85
|
-
fired_sessions.each do |s,rw|
|
|
86
|
-
s.ev_do_handle_events(rw[:r],rw[:w])
|
|
87
|
+
|
|
88
|
+
fired_sessions.each do |s, rw|
|
|
89
|
+
s.ev_do_handle_events(rw[:r], rw[:w])
|
|
87
90
|
end
|
|
88
|
-
|
|
91
|
+
|
|
89
92
|
@sessions.each { |s| s.ev_do_postprocess(fired_sessions.key?(s)) }
|
|
90
93
|
true
|
|
91
94
|
end
|
|
@@ -97,18 +100,21 @@ module Net
|
|
|
97
100
|
# we call block with session as argument
|
|
98
101
|
def ev_preprocess(&block)
|
|
99
102
|
return false if block_given? && !yield(@sessions.first)
|
|
103
|
+
|
|
100
104
|
@sessions.each(&:ev_preprocess)
|
|
101
105
|
return false if block_given? && !yield(@sessions.first)
|
|
106
|
+
|
|
102
107
|
return true
|
|
103
108
|
end
|
|
104
|
-
|
|
109
|
+
|
|
105
110
|
def ev_select_and_postprocess(wait)
|
|
106
111
|
raise "Only one session expected" unless @sessions.count == 1
|
|
112
|
+
|
|
107
113
|
session = @sessions.first
|
|
108
|
-
sr,sw,actwait = session.ev_do_calculate_rw_wait(wait)
|
|
114
|
+
sr, sw, actwait = session.ev_do_calculate_rw_wait(wait)
|
|
109
115
|
readers, writers, = IO.select(sr, sw, nil, actwait)
|
|
110
|
-
|
|
111
|
-
session.ev_do_handle_events(readers,writers)
|
|
116
|
+
|
|
117
|
+
session.ev_do_handle_events(readers, writers)
|
|
112
118
|
session.ev_do_postprocess(!((readers.nil? || readers.empty?) && (writers.nil? || writers.empty?)))
|
|
113
119
|
end
|
|
114
120
|
end
|