net-ssh 5.0.2 → 7.0.1
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/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +87 -0
- data/.github/workflows/rubocop.yml +13 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +19 -2
- data/.rubocop_todo.yml +623 -511
- data/CHANGES.txt +76 -0
- data/Dockerfile +27 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +2 -0
- data/Gemfile.noed25519 +2 -0
- data/Manifest +0 -1
- data/README.md +293 -0
- data/Rakefile +6 -2
- data/appveyor.yml +4 -2
- data/docker-compose.yml +23 -0
- data/lib/net/ssh/authentication/agent.rb +36 -14
- data/lib/net/ssh/authentication/certificate.rb +19 -7
- data/lib/net/ssh/authentication/constants.rb +0 -1
- data/lib/net/ssh/authentication/ed25519.rb +83 -50
- data/lib/net/ssh/authentication/ed25519_loader.rb +5 -8
- data/lib/net/ssh/authentication/key_manager.rb +74 -33
- 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 +5 -3
- 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 +58 -16
- data/lib/net/ssh/authentication/pageant.rb +97 -97
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -3
- data/lib/net/ssh/authentication/session.rb +27 -23
- data/lib/net/ssh/buffer.rb +91 -40
- data/lib/net/ssh/buffered_io.rb +24 -26
- data/lib/net/ssh/config.rb +99 -53
- data/lib/net/ssh/connection/channel.rb +101 -87
- data/lib/net/ssh/connection/constants.rb +0 -4
- data/lib/net/ssh/connection/event_loop.rb +30 -25
- data/lib/net/ssh/connection/keepalive.rb +12 -12
- data/lib/net/ssh/connection/session.rb +115 -111
- data/lib/net/ssh/connection/term.rb +56 -58
- data/lib/net/ssh/errors.rb +12 -12
- data/lib/net/ssh/key_factory.rb +108 -22
- data/lib/net/ssh/known_hosts.rb +120 -36
- data/lib/net/ssh/loggable.rb +10 -11
- data/lib/net/ssh/packet.rb +1 -1
- data/lib/net/ssh/prompt.rb +9 -11
- data/lib/net/ssh/proxy/command.rb +1 -2
- 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 -6
- data/lib/net/ssh/service/forward.rb +9 -8
- data/lib/net/ssh/test/channel.rb +24 -26
- data/lib/net/ssh/test/extensions.rb +37 -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 +12 -12
- data/lib/net/ssh/transport/algorithms.rb +177 -118
- data/lib/net/ssh/transport/cipher_factory.rb +34 -50
- data/lib/net/ssh/transport/constants.rb +13 -9
- data/lib/net/ssh/transport/ctr.rb +8 -14
- 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/sha2_256.rb +7 -11
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +13 -11
- data/lib/net/ssh/transport/identity_cipher.rb +11 -13
- data/lib/net/ssh/transport/kex/abstract.rb +130 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +5 -19
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +30 -139
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -8
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +20 -81
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +5 -4
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +5 -4
- data/lib/net/ssh/transport/kex.rb +15 -10
- data/lib/net/ssh/transport/key_expander.rb +7 -8
- data/lib/net/ssh/transport/openssl.rb +149 -111
- data/lib/net/ssh/transport/packet_stream.rb +53 -22
- data/lib/net/ssh/transport/server_version.rb +17 -16
- data/lib/net/ssh/transport/session.rb +35 -11
- data/lib/net/ssh/transport/state.rb +44 -44
- data/lib/net/ssh/verifiers/accept_new.rb +7 -2
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
- data/lib/net/ssh/verifiers/always.rb +10 -4
- data/lib/net/ssh/verifiers/never.rb +4 -2
- data/lib/net/ssh/version.rb +2 -2
- data/lib/net/ssh.rb +17 -9
- data/net-ssh-public_cert.pem +18 -19
- data/net-ssh.gemspec +9 -7
- data/support/ssh_tunnel_bug.rb +3 -3
- data.tar.gz.sig +0 -0
- metadata +65 -41
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -52
- data/Gemfile.noed25519.lock +0 -41
- data/README.rdoc +0 -169
- data/lib/net/ssh/ruby_compat.rb +0 -13
- data/support/arcfour_check.rb +0 -20
data/lib/net/ssh/proxy/socks5.rb
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
require 'socket'
|
|
2
|
-
require 'net/ssh/ruby_compat'
|
|
3
2
|
require 'net/ssh/proxy/errors'
|
|
4
3
|
|
|
5
4
|
module Net
|
|
6
5
|
module SSH
|
|
7
6
|
module Proxy
|
|
8
|
-
|
|
9
7
|
# An implementation of a SOCKS5 proxy. To use it, instantiate it, then
|
|
10
8
|
# pass the instantiated object via the :proxy key to Net::SSH.start:
|
|
11
9
|
#
|
|
@@ -54,7 +52,7 @@ module Net
|
|
|
54
52
|
# Create a new proxy connection to the given proxy host and port.
|
|
55
53
|
# Optionally, :user and :password options may be given to
|
|
56
54
|
# identify the username and password with which to authenticate.
|
|
57
|
-
def initialize(proxy_host, proxy_port=1080, options={})
|
|
55
|
+
def initialize(proxy_host, proxy_port = 1080, options = {})
|
|
58
56
|
@proxy_host = proxy_host
|
|
59
57
|
@proxy_port = proxy_port
|
|
60
58
|
@options = options
|
|
@@ -95,7 +93,7 @@ module Net
|
|
|
95
93
|
|
|
96
94
|
packet << [port].pack("n")
|
|
97
95
|
socket.send packet, 0
|
|
98
|
-
|
|
96
|
+
|
|
99
97
|
version, reply, = socket.recv(2).unpack("C*")
|
|
100
98
|
socket.recv(1)
|
|
101
99
|
address_type = socket.recv(1).getbyte(0)
|
|
@@ -112,7 +110,7 @@ module Net
|
|
|
112
110
|
raise ConnectError, "Illegal response type"
|
|
113
111
|
end
|
|
114
112
|
portnum = socket.recv(2)
|
|
115
|
-
|
|
113
|
+
|
|
116
114
|
unless reply == SUCCESS
|
|
117
115
|
socket.close
|
|
118
116
|
raise ConnectError, "#{reply}"
|
|
@@ -137,7 +135,6 @@ module Net
|
|
|
137
135
|
end
|
|
138
136
|
end
|
|
139
137
|
end
|
|
140
|
-
|
|
141
138
|
end
|
|
142
139
|
end
|
|
143
140
|
end
|
|
@@ -3,7 +3,6 @@ require 'net/ssh/loggable'
|
|
|
3
3
|
module Net
|
|
4
4
|
module SSH
|
|
5
5
|
module Service
|
|
6
|
-
|
|
7
6
|
# This class implements various port forwarding services for use by
|
|
8
7
|
# Net::SSH clients. The Forward class should never need to be instantiated
|
|
9
8
|
# directly; instead, it should be accessed via the singleton instance
|
|
@@ -18,7 +17,7 @@ module Net
|
|
|
18
17
|
attr_reader :session
|
|
19
18
|
|
|
20
19
|
# A simple class for representing a requested remote forwarded port.
|
|
21
|
-
Remote = Struct.new(:host, :port)
|
|
20
|
+
Remote = Struct.new(:host, :port) # :nodoc:
|
|
22
21
|
|
|
23
22
|
# Instantiates a new Forward service instance atop the given connection
|
|
24
23
|
# service session. This will register new channel open handlers to handle
|
|
@@ -85,7 +84,8 @@ module Net
|
|
|
85
84
|
client = server.accept
|
|
86
85
|
debug { "received connection on #{socket}" }
|
|
87
86
|
|
|
88
|
-
channel = session.open_channel("direct-tcpip", :string, remote_host, :long,
|
|
87
|
+
channel = session.open_channel("direct-tcpip", :string, remote_host, :long,
|
|
88
|
+
remote_port, :string, bind_address, local_port_type, local_port) do |achannel|
|
|
89
89
|
achannel.info { "direct channel established" }
|
|
90
90
|
end
|
|
91
91
|
|
|
@@ -105,7 +105,7 @@ module Net
|
|
|
105
105
|
#
|
|
106
106
|
# ssh.forward.cancel_local(1234)
|
|
107
107
|
# ssh.forward.cancel_local(1234, "0.0.0.0")
|
|
108
|
-
def cancel_local(port, bind_address="127.0.0.1")
|
|
108
|
+
def cancel_local(port, bind_address = "127.0.0.1")
|
|
109
109
|
socket = @local_forwarded_ports.delete([port, bind_address])
|
|
110
110
|
socket.shutdown rescue nil
|
|
111
111
|
socket.close rescue nil
|
|
@@ -214,7 +214,7 @@ module Net
|
|
|
214
214
|
# raise Net::SSH::Exception, "remote forwarding request failed"
|
|
215
215
|
# end
|
|
216
216
|
#
|
|
217
|
-
def remote(port, host, remote_port, remote_host="127.0.0.1")
|
|
217
|
+
def remote(port, host, remote_port, remote_host = "127.0.0.1")
|
|
218
218
|
session.send_global_request("tcpip-forward", :string, remote_host, :long, remote_port) do |success, response|
|
|
219
219
|
if success
|
|
220
220
|
remote_port = response.read_long if remote_port == 0
|
|
@@ -248,7 +248,7 @@ module Net
|
|
|
248
248
|
#
|
|
249
249
|
# ssh.forward.cancel_remote(1234, "0.0.0.0")
|
|
250
250
|
# ssh.loop { ssh.forward.active_remotes.include?([1234, "0.0.0.0"]) }
|
|
251
|
-
def cancel_remote(port, host="127.0.0.1")
|
|
251
|
+
def cancel_remote(port, host = "127.0.0.1")
|
|
252
252
|
session.send_global_request("cancel-tcpip-forward", :string, host, :long, port) do |success, response|
|
|
253
253
|
if success
|
|
254
254
|
@remote_forwarded_ports.delete([port, host])
|
|
@@ -289,6 +289,7 @@ module Net
|
|
|
289
289
|
# end
|
|
290
290
|
def agent(channel)
|
|
291
291
|
return if @agent_forwarded
|
|
292
|
+
|
|
292
293
|
@agent_forwarded = true
|
|
293
294
|
|
|
294
295
|
channel.send_channel_request("auth-agent-req@openssh.com") do |achannel, success|
|
|
@@ -387,12 +388,13 @@ module Net
|
|
|
387
388
|
originator_address = packet.read_string
|
|
388
389
|
originator_port = packet.read_long
|
|
389
390
|
|
|
391
|
+
puts "REMOTE 0: #{connected_port} #{connected_address} #{originator_address} #{originator_port}"
|
|
390
392
|
remote = @remote_forwarded_ports[[connected_port, connected_address]]
|
|
391
|
-
|
|
392
393
|
if remote.nil?
|
|
393
394
|
raise Net::SSH::ChannelOpenFailed.new(1, "unknown request from remote forwarded connection on #{connected_address}:#{connected_port}")
|
|
394
395
|
end
|
|
395
396
|
|
|
397
|
+
puts "REMOTE: #{remote.host} #{remote.port}"
|
|
396
398
|
client = TCPSocket.new(remote.host, remote.port)
|
|
397
399
|
info { "connected #{connected_address}:#{connected_port} originator #{originator_address}:#{originator_port}" }
|
|
398
400
|
|
|
@@ -419,7 +421,6 @@ module Net
|
|
|
419
421
|
end
|
|
420
422
|
end
|
|
421
423
|
end
|
|
422
|
-
|
|
423
424
|
end
|
|
424
425
|
end
|
|
425
426
|
end
|
data/lib/net/ssh/test/channel.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
module Net
|
|
2
|
-
module SSH
|
|
1
|
+
module Net
|
|
2
|
+
module SSH
|
|
3
3
|
module Test
|
|
4
|
-
|
|
5
4
|
# A mock channel, used for scripting actions in tests. It wraps a
|
|
6
5
|
# Net::SSH::Test::Script instance, and delegates to it for the most part.
|
|
7
6
|
# This class has little real functionality on its own, but rather acts as
|
|
@@ -19,34 +18,34 @@ module Net
|
|
|
19
18
|
class Channel
|
|
20
19
|
# The Net::SSH::Test::Script instance employed by this mock channel.
|
|
21
20
|
attr_reader :script
|
|
22
|
-
|
|
21
|
+
|
|
23
22
|
# Sets the local-id of this channel object (the id assigned by the client).
|
|
24
23
|
attr_writer :local_id
|
|
25
|
-
|
|
24
|
+
|
|
26
25
|
# Sets the remote-id of this channel object (the id assigned by the mock-server).
|
|
27
26
|
attr_writer :remote_id
|
|
28
|
-
|
|
27
|
+
|
|
29
28
|
# Creates a new Test::Channel instance on top of the given +script+ (which
|
|
30
29
|
# must be a Net::SSH::Test::Script instance).
|
|
31
30
|
def initialize(script)
|
|
32
31
|
@script = script
|
|
33
32
|
@local_id = @remote_id = nil
|
|
34
33
|
end
|
|
35
|
-
|
|
34
|
+
|
|
36
35
|
# Returns the local (client-assigned) id for this channel, or a Proc object
|
|
37
36
|
# that will return the local-id later if the local id has not yet been set.
|
|
38
37
|
# (See Net::SSH::Test::Packet#instantiate!.)
|
|
39
38
|
def local_id
|
|
40
39
|
@local_id || Proc.new { @local_id or raise "local-id has not been set yet!" }
|
|
41
40
|
end
|
|
42
|
-
|
|
41
|
+
|
|
43
42
|
# Returns the remote (server-assigned) id for this channel, or a Proc object
|
|
44
43
|
# that will return the remote-id later if the remote id has not yet been set.
|
|
45
44
|
# (See Net::SSH::Test::Packet#instantiate!.)
|
|
46
45
|
def remote_id
|
|
47
46
|
@remote_id || Proc.new { @remote_id or raise "remote-id has not been set yet!" }
|
|
48
47
|
end
|
|
49
|
-
|
|
48
|
+
|
|
50
49
|
# Because adjacent calls to #gets_data will sometimes cause the data packets
|
|
51
50
|
# to be concatenated (causing expectations in tests to fail), you may
|
|
52
51
|
# need to separate those calls with calls to #inject_remote_delay! (which
|
|
@@ -58,62 +57,62 @@ module Net
|
|
|
58
57
|
def inject_remote_delay!
|
|
59
58
|
gets_data("")
|
|
60
59
|
end
|
|
61
|
-
|
|
62
|
-
# Scripts the sending of an "exec" channel request packet to the mock
|
|
60
|
+
|
|
61
|
+
# Scripts the sending of an "exec" channel request packet to the mock
|
|
63
62
|
# server. If +reply+ is true, then the server is expected to reply to the
|
|
64
63
|
# request, otherwise no response to this request will be sent. If +success+
|
|
65
64
|
# is +true+, then the request will be successful, otherwise a failure will
|
|
66
65
|
# be scripted.
|
|
67
66
|
#
|
|
68
67
|
# channel.sends_exec "ls -l"
|
|
69
|
-
def sends_exec(command, reply=true, success=true)
|
|
68
|
+
def sends_exec(command, reply = true, success = true)
|
|
70
69
|
script.sends_channel_request(self, "exec", reply, command, success)
|
|
71
70
|
end
|
|
72
|
-
|
|
71
|
+
|
|
73
72
|
# Scripts the sending of a "subsystem" channel request packet to the mock
|
|
74
73
|
# server. See #sends_exec for a discussion of the meaning of the +reply+
|
|
75
74
|
# and +success+ arguments.
|
|
76
75
|
#
|
|
77
76
|
# channel.sends_subsystem "sftp"
|
|
78
|
-
def sends_subsystem(subsystem, reply=true, success=true)
|
|
77
|
+
def sends_subsystem(subsystem, reply = true, success = true)
|
|
79
78
|
script.sends_channel_request(self, "subsystem", reply, subsystem, success)
|
|
80
79
|
end
|
|
81
|
-
|
|
80
|
+
|
|
82
81
|
# Scripts the sending of a data packet across the channel.
|
|
83
82
|
#
|
|
84
83
|
# channel.sends_data "foo"
|
|
85
84
|
def sends_data(data)
|
|
86
85
|
script.sends_channel_data(self, data)
|
|
87
86
|
end
|
|
88
|
-
|
|
87
|
+
|
|
89
88
|
# Scripts the sending of an EOF packet across the channel.
|
|
90
89
|
#
|
|
91
90
|
# channel.sends_eof
|
|
92
91
|
def sends_eof
|
|
93
92
|
script.sends_channel_eof(self)
|
|
94
93
|
end
|
|
95
|
-
|
|
94
|
+
|
|
96
95
|
# Scripts the sending of a "channel close" packet across the channel.
|
|
97
96
|
#
|
|
98
97
|
# channel.sends_close
|
|
99
98
|
def sends_close
|
|
100
99
|
script.sends_channel_close(self)
|
|
101
100
|
end
|
|
102
|
-
|
|
101
|
+
|
|
103
102
|
# Scripts the sending of a "request pty" request packet across the channel.
|
|
104
103
|
#
|
|
105
104
|
# channel.sends_request_pty
|
|
106
105
|
def sends_request_pty
|
|
107
106
|
script.sends_channel_request_pty(self)
|
|
108
107
|
end
|
|
109
|
-
|
|
108
|
+
|
|
110
109
|
# Scripts the reception of a channel data packet from the remote end.
|
|
111
110
|
#
|
|
112
111
|
# channel.gets_data "bar"
|
|
113
112
|
def gets_data(data)
|
|
114
113
|
script.gets_channel_data(self, data)
|
|
115
114
|
end
|
|
116
|
-
|
|
115
|
+
|
|
117
116
|
# Scripts the reception of a channel extended data packet from the remote
|
|
118
117
|
# end.
|
|
119
118
|
#
|
|
@@ -121,21 +120,21 @@ module Net
|
|
|
121
120
|
def gets_extended_data(data)
|
|
122
121
|
script.gets_channel_extended_data(self, data)
|
|
123
122
|
end
|
|
124
|
-
|
|
123
|
+
|
|
125
124
|
# Scripts the reception of an "exit-status" channel request packet.
|
|
126
125
|
#
|
|
127
126
|
# channel.gets_exit_status(127)
|
|
128
|
-
def gets_exit_status(status=0)
|
|
127
|
+
def gets_exit_status(status = 0)
|
|
129
128
|
script.gets_channel_request(self, "exit-status", false, status)
|
|
130
129
|
end
|
|
131
|
-
|
|
130
|
+
|
|
132
131
|
# Scripts the reception of an EOF packet from the remote end.
|
|
133
132
|
#
|
|
134
133
|
# channel.gets_eof
|
|
135
134
|
def gets_eof
|
|
136
135
|
script.gets_channel_eof(self)
|
|
137
136
|
end
|
|
138
|
-
|
|
137
|
+
|
|
139
138
|
# Scripts the reception of a "channel close" packet from the remote end.
|
|
140
139
|
#
|
|
141
140
|
# channel.gets_close
|
|
@@ -143,7 +142,6 @@ module Net
|
|
|
143
142
|
script.gets_channel_close(self)
|
|
144
143
|
end
|
|
145
144
|
end
|
|
146
|
-
|
|
147
145
|
end
|
|
148
146
|
end
|
|
149
|
-
end
|
|
147
|
+
end
|
|
@@ -6,16 +6,14 @@ require 'net/ssh/connection/constants'
|
|
|
6
6
|
require 'net/ssh/transport/constants'
|
|
7
7
|
require 'net/ssh/transport/packet_stream'
|
|
8
8
|
|
|
9
|
-
module Net
|
|
10
|
-
module SSH
|
|
9
|
+
module Net
|
|
10
|
+
module SSH
|
|
11
11
|
module Test
|
|
12
|
-
|
|
13
12
|
# A collection of modules used to extend/override the default behavior of
|
|
14
13
|
# Net::SSH internals for ease of testing. As a consumer of Net::SSH, you'll
|
|
15
14
|
# never need to use this directly--they're all used under the covers by
|
|
16
15
|
# the Net::SSH::Test system.
|
|
17
16
|
module Extensions
|
|
18
|
-
|
|
19
17
|
# An extension to Net::SSH::BufferedIo (assumes that the underlying IO
|
|
20
18
|
# is actually a StringIO). Facilitates unit testing.
|
|
21
19
|
module BufferedIo
|
|
@@ -24,80 +22,82 @@ module Net
|
|
|
24
22
|
def select_for_read?
|
|
25
23
|
pos < size
|
|
26
24
|
end
|
|
27
|
-
|
|
25
|
+
|
|
28
26
|
# Set this to +true+ if you want the IO to pretend to be available for writing
|
|
29
27
|
attr_accessor :select_for_write
|
|
30
|
-
|
|
28
|
+
|
|
31
29
|
# Set this to +true+ if you want the IO to pretend to be in an error state
|
|
32
30
|
attr_accessor :select_for_error
|
|
33
|
-
|
|
31
|
+
|
|
34
32
|
alias select_for_write? select_for_write
|
|
35
33
|
alias select_for_error? select_for_error
|
|
36
34
|
end
|
|
37
|
-
|
|
35
|
+
|
|
38
36
|
# An extension to Net::SSH::Transport::PacketStream (assumes that the
|
|
39
37
|
# underlying IO is actually a StringIO). Facilitates unit testing.
|
|
40
38
|
module PacketStream
|
|
41
39
|
include BufferedIo # make sure we get the extensions here, too
|
|
42
|
-
|
|
43
|
-
def self.included(base)
|
|
40
|
+
|
|
41
|
+
def self.included(base) # :nodoc:
|
|
44
42
|
base.send :alias_method, :real_available_for_read?, :available_for_read?
|
|
45
43
|
base.send :alias_method, :available_for_read?, :test_available_for_read?
|
|
46
|
-
|
|
44
|
+
|
|
47
45
|
base.send :alias_method, :real_enqueue_packet, :enqueue_packet
|
|
48
46
|
base.send :alias_method, :enqueue_packet, :test_enqueue_packet
|
|
49
|
-
|
|
47
|
+
|
|
50
48
|
base.send :alias_method, :real_poll_next_packet, :poll_next_packet
|
|
51
49
|
base.send :alias_method, :poll_next_packet, :test_poll_next_packet
|
|
52
50
|
end
|
|
53
|
-
|
|
51
|
+
|
|
54
52
|
# Called when another packet should be inspected from the current
|
|
55
53
|
# script. If the next packet is a remote packet, it pops it off the
|
|
56
54
|
# script and shoves it onto this IO object, making it available to
|
|
57
55
|
# be read.
|
|
58
56
|
def idle!
|
|
59
57
|
return false unless script.next(:first)
|
|
60
|
-
|
|
58
|
+
|
|
61
59
|
if script.next(:first).remote?
|
|
62
60
|
self.string << script.next.to_s
|
|
63
61
|
self.pos = pos
|
|
64
62
|
end
|
|
65
|
-
|
|
63
|
+
|
|
66
64
|
return true
|
|
67
65
|
end
|
|
68
|
-
|
|
66
|
+
|
|
69
67
|
# The testing version of Net::SSH::Transport::PacketStream#available_for_read?.
|
|
70
68
|
# Returns true if there is data pending to be read. Otherwise calls #idle!.
|
|
71
69
|
def test_available_for_read?
|
|
72
70
|
return true if select_for_read?
|
|
71
|
+
|
|
73
72
|
idle!
|
|
74
73
|
false
|
|
75
74
|
end
|
|
76
|
-
|
|
75
|
+
|
|
77
76
|
# The testing version of Net::SSH::Transport::PacketStream#enqueued_packet.
|
|
78
77
|
# Simply calls Net::SSH::Test::Script#process on the packet.
|
|
79
78
|
def test_enqueue_packet(payload)
|
|
80
79
|
packet = Net::SSH::Buffer.new(payload.to_s)
|
|
81
80
|
script.process(packet)
|
|
82
81
|
end
|
|
83
|
-
|
|
82
|
+
|
|
84
83
|
# The testing version of Net::SSH::Transport::PacketStream#poll_next_packet.
|
|
85
84
|
# Reads the next available packet from the IO object and returns it.
|
|
86
85
|
def test_poll_next_packet
|
|
87
86
|
return nil if available <= 0
|
|
87
|
+
|
|
88
88
|
packet = Net::SSH::Buffer.new(read_available(4))
|
|
89
89
|
length = packet.read_long
|
|
90
90
|
Net::SSH::Packet.new(read_available(length))
|
|
91
91
|
end
|
|
92
92
|
end
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
# An extension to Net::SSH::Connection::Channel. Facilitates unit testing.
|
|
95
95
|
module Channel
|
|
96
|
-
def self.included(base)
|
|
96
|
+
def self.included(base) # :nodoc:
|
|
97
97
|
base.send :alias_method, :send_data_for_real, :send_data
|
|
98
98
|
base.send :alias_method, :send_data, :send_data_for_test
|
|
99
99
|
end
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
# The testing version of Net::SSH::Connection::Channel#send_data. Calls
|
|
102
102
|
# the original implementation, and then immediately enqueues the data for
|
|
103
103
|
# output so that scripted sends are properly interpreted as discrete
|
|
@@ -107,16 +107,16 @@ module Net
|
|
|
107
107
|
enqueue_pending_output
|
|
108
108
|
end
|
|
109
109
|
end
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
# An extension to the built-in ::IO class. Simply redefines IO.select
|
|
112
112
|
# so that it can be scripted in Net::SSH unit tests.
|
|
113
113
|
module IO
|
|
114
|
-
def self.included(base)
|
|
114
|
+
def self.included(base) # :nodoc:
|
|
115
115
|
base.extend(ClassMethods)
|
|
116
116
|
end
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
@extension_enabled = false
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
def self.with_test_extension(&block)
|
|
121
121
|
orig_value = @extension_enabled
|
|
122
122
|
@extension_enabled = true
|
|
@@ -126,41 +126,43 @@ module Net
|
|
|
126
126
|
@extension_enabled = orig_value
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
|
-
|
|
129
|
+
|
|
130
130
|
def self.extension_enabled?
|
|
131
131
|
@extension_enabled
|
|
132
132
|
end
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
module ClassMethods
|
|
135
|
-
def self.extended(obj)
|
|
136
|
-
class <<obj
|
|
135
|
+
def self.extended(obj) # :nodoc:
|
|
136
|
+
class << obj
|
|
137
137
|
alias_method :select_for_real, :select
|
|
138
138
|
alias_method :select, :select_for_test
|
|
139
139
|
end
|
|
140
140
|
end
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
# The testing version of ::IO.select. Assumes that all readers,
|
|
143
143
|
# writers, and errors arrays are either nil, or contain only objects
|
|
144
144
|
# that mix in Net::SSH::Test::Extensions::BufferedIo.
|
|
145
|
-
def select_for_test(readers=nil, writers=nil, errors=nil, wait=nil)
|
|
145
|
+
def select_for_test(readers = nil, writers = nil, errors = nil, wait = nil)
|
|
146
146
|
return select_for_real(readers, writers, errors, wait) unless Net::SSH::Test::Extensions::IO.extension_enabled?
|
|
147
|
+
|
|
147
148
|
ready_readers = Array(readers).select { |r| r.select_for_read? }
|
|
148
149
|
ready_writers = Array(writers).select { |r| r.select_for_write? }
|
|
149
150
|
ready_errors = Array(errors).select { |r| r.select_for_error? }
|
|
150
|
-
|
|
151
|
+
|
|
151
152
|
return [ready_readers, ready_writers, ready_errors] if ready_readers.any? || ready_writers.any? || ready_errors.any?
|
|
152
|
-
|
|
153
|
+
|
|
153
154
|
processed = 0
|
|
154
155
|
Array(readers).each do |reader|
|
|
155
156
|
processed += 1 if reader.idle!
|
|
156
157
|
end
|
|
157
|
-
|
|
158
|
+
|
|
158
159
|
raise "no readers were ready for reading, and none had any incoming packets" if processed == 0 && wait != 0
|
|
160
|
+
|
|
161
|
+
[[], [], []]
|
|
159
162
|
end
|
|
160
163
|
end
|
|
161
164
|
end
|
|
162
165
|
end
|
|
163
|
-
|
|
164
166
|
end
|
|
165
167
|
end
|
|
166
168
|
end
|
data/lib/net/ssh/test/kex.rb
CHANGED
|
@@ -5,10 +5,9 @@ require 'net/ssh/transport/algorithms'
|
|
|
5
5
|
require 'net/ssh/transport/constants'
|
|
6
6
|
require 'net/ssh/transport/kex'
|
|
7
7
|
|
|
8
|
-
module Net
|
|
9
|
-
module SSH
|
|
8
|
+
module Net
|
|
9
|
+
module SSH
|
|
10
10
|
module Test
|
|
11
|
-
|
|
12
11
|
# An implementation of a key-exchange strategy specifically for unit tests.
|
|
13
12
|
# (This strategy would never really work against a real SSH server--it makes
|
|
14
13
|
# too many assumptions about the server's response.)
|
|
@@ -17,29 +16,28 @@ module Net
|
|
|
17
16
|
# "test" algorithm.
|
|
18
17
|
class Kex
|
|
19
18
|
include Net::SSH::Transport::Constants
|
|
20
|
-
|
|
19
|
+
|
|
21
20
|
# Creates a new instance of the testing key-exchange algorithm with the
|
|
22
21
|
# given arguments.
|
|
23
22
|
def initialize(algorithms, connection, data)
|
|
24
23
|
@connection = connection
|
|
25
24
|
end
|
|
26
|
-
|
|
25
|
+
|
|
27
26
|
# Exchange keys with the server. This returns a hash of constant values,
|
|
28
27
|
# and does not actually exchange keys.
|
|
29
28
|
def exchange_keys
|
|
30
29
|
result = Net::SSH::Buffer.from(:byte, NEWKEYS)
|
|
31
30
|
@connection.send_message(result)
|
|
32
|
-
|
|
31
|
+
|
|
33
32
|
buffer = @connection.next_message
|
|
34
33
|
raise Net::SSH::Exception, "expected NEWKEYS" unless buffer.type == NEWKEYS
|
|
35
|
-
|
|
34
|
+
|
|
36
35
|
{ session_id: "abc-xyz",
|
|
37
36
|
server_key: OpenSSL::PKey::RSA.new(512),
|
|
38
37
|
shared_secret: OpenSSL::BN.new("1234567890", 10),
|
|
39
38
|
hashing_algorithm: OpenSSL::Digest::SHA1 }
|
|
40
39
|
end
|
|
41
40
|
end
|
|
42
|
-
|
|
43
41
|
end
|
|
44
42
|
end
|
|
45
43
|
end
|
|
@@ -4,7 +4,6 @@ require 'net/ssh/test/packet'
|
|
|
4
4
|
module Net
|
|
5
5
|
module SSH
|
|
6
6
|
module Test
|
|
7
|
-
|
|
8
7
|
# This is a specialization of Net::SSH::Test::Packet for representing mock
|
|
9
8
|
# packets that are sent from the local (client) host. These are created
|
|
10
9
|
# automatically by Net::SSH::Test::Script and Net::SSH::Test::Channel by any
|
|
@@ -49,7 +48,6 @@ module Net
|
|
|
49
48
|
end
|
|
50
49
|
end
|
|
51
50
|
end
|
|
52
|
-
|
|
53
51
|
end
|
|
54
52
|
end
|
|
55
53
|
end
|
data/lib/net/ssh/test/packet.rb
CHANGED
|
@@ -4,7 +4,6 @@ require 'net/ssh/transport/constants'
|
|
|
4
4
|
module Net
|
|
5
5
|
module SSH
|
|
6
6
|
module Test
|
|
7
|
-
|
|
8
7
|
# This is an abstract class, not to be instantiated directly, subclassed by
|
|
9
8
|
# Net::SSH::Test::LocalPacket and Net::SSH::Test::RemotePacket. It implements
|
|
10
9
|
# functionality common to those subclasses.
|
|
@@ -70,7 +69,7 @@ module Net
|
|
|
70
69
|
# added. Unsupported packet types will otherwise raise an exception.
|
|
71
70
|
def types
|
|
72
71
|
@types ||= case @type
|
|
73
|
-
when KEXINIT
|
|
72
|
+
when KEXINIT
|
|
74
73
|
%i[long long long long
|
|
75
74
|
string string string string string string string string string string
|
|
76
75
|
bool]
|
|
@@ -83,13 +82,14 @@ module Net
|
|
|
83
82
|
when CHANNEL_REQUEST
|
|
84
83
|
parts = %i[long string bool]
|
|
85
84
|
case @data[1]
|
|
86
|
-
when "exec", "subsystem","shell" then parts << :string
|
|
85
|
+
when "exec", "subsystem", "shell" then parts << :string
|
|
87
86
|
when "exit-status" then parts << :long
|
|
88
87
|
when "pty-req" then parts.concat(%i[string long long long long string])
|
|
89
88
|
when "env" then parts.contact(%i[string string])
|
|
90
89
|
else
|
|
91
90
|
request = Packet.registered_channel_requests(@data[1])
|
|
92
91
|
raise "don't know what to do about #{@data[1]} channel request" unless request
|
|
92
|
+
|
|
93
93
|
parts.concat(request[:extra_parts])
|
|
94
94
|
end
|
|
95
95
|
else raise "don't know how to parse packet type #{@type}"
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
require 'net/ssh/buffer'
|
|
2
2
|
require 'net/ssh/test/packet'
|
|
3
3
|
|
|
4
|
-
module Net
|
|
5
|
-
module SSH
|
|
4
|
+
module Net
|
|
5
|
+
module SSH
|
|
6
6
|
module Test
|
|
7
|
-
|
|
8
7
|
# This is a specialization of Net::SSH::Test::Packet for representing mock
|
|
9
8
|
# packets that are received by the local (client) host. These are created
|
|
10
9
|
# automatically by Net::SSH::Test::Script and Net::SSH::Test::Channel by any
|
|
@@ -14,7 +13,7 @@ module Net
|
|
|
14
13
|
def remote?
|
|
15
14
|
true
|
|
16
15
|
end
|
|
17
|
-
|
|
16
|
+
|
|
18
17
|
# The #process method should only be called on Net::SSH::Test::LocalPacket
|
|
19
18
|
# packets; if it is attempted on a remote packet, then it is an expectation
|
|
20
19
|
# mismatch (a remote packet was received when a local packet was expected
|
|
@@ -23,8 +22,8 @@ module Net
|
|
|
23
22
|
def process(packet)
|
|
24
23
|
raise "received packet type #{packet.read_byte} and was not expecting any packet"
|
|
25
24
|
end
|
|
26
|
-
|
|
27
|
-
# Returns this remote packet as a string, suitable for parsing by
|
|
25
|
+
|
|
26
|
+
# Returns this remote packet as a string, suitable for parsing by
|
|
28
27
|
# Net::SSH::Transport::PacketStream and friends. When a remote packet is
|
|
29
28
|
# received, this method is called and the result concatenated onto the
|
|
30
29
|
# input buffer for the packet stream.
|
|
@@ -36,7 +35,6 @@ module Net
|
|
|
36
35
|
end
|
|
37
36
|
end
|
|
38
37
|
end
|
|
39
|
-
|
|
40
38
|
end
|
|
41
39
|
end
|
|
42
|
-
end
|
|
40
|
+
end
|