net-ssh 5.2.0 → 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 +5 -5
- 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 +16 -2
- data/.rubocop_todo.yml +623 -511
- data/CHANGES.txt +50 -2
- 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 +29 -13
- 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 +13 -8
- data/lib/net/ssh/authentication/ed25519_loader.rb +5 -8
- data/lib/net/ssh/authentication/key_manager.rb +73 -32
- 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 +56 -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 +51 -40
- data/lib/net/ssh/buffered_io.rb +24 -26
- data/lib/net/ssh/config.rb +82 -50
- 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 +10 -13
- data/lib/net/ssh/known_hosts.rb +106 -39
- 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 +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 +7 -7
- data/lib/net/ssh/transport/algorithms.rb +100 -58
- 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 -127
- data/lib/net/ssh/transport/packet_stream.rb +50 -16
- 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 +3 -3
- data/lib/net/ssh.rb +12 -8
- data/net-ssh-public_cert.pem +8 -8
- data/net-ssh.gemspec +9 -7
- data/support/ssh_tunnel_bug.rb +3 -3
- data.tar.gz.sig +0 -0
- metadata +55 -30
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -53
- data/Gemfile.noed25519.lock +0 -41
- data/README.rdoc +0 -194
- data/lib/net/ssh/ruby_compat.rb +0 -13
- data/support/arcfour_check.rb +0 -20
data/lib/net/ssh/prompt.rb
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
require 'io/console'
|
|
2
2
|
|
|
3
|
-
module Net
|
|
3
|
+
module Net
|
|
4
4
|
module SSH
|
|
5
|
-
|
|
6
5
|
# Default prompt implementation, called for asking password from user.
|
|
7
6
|
# It will never be instantiated directly, but will instead be created for
|
|
8
7
|
# you automatically.
|
|
@@ -13,8 +12,8 @@ module Net
|
|
|
13
12
|
#
|
|
14
13
|
# prompter = options[:password_prompt].start({type:'password'})
|
|
15
14
|
# while !ok && max_retries < 3
|
|
16
|
-
# user = prompter.ask("user: ",
|
|
17
|
-
# password = prompter.ask("password: ",
|
|
15
|
+
# user = prompter.ask("user: ", true)
|
|
16
|
+
# password = prompter.ask("password: ", false)
|
|
18
17
|
# ok = send(user, password)
|
|
19
18
|
# prompter.sucess if ok
|
|
20
19
|
# end
|
|
@@ -24,9 +23,9 @@ module Net
|
|
|
24
23
|
def self.default(options = {})
|
|
25
24
|
@default ||= new(options)
|
|
26
25
|
end
|
|
27
|
-
|
|
26
|
+
|
|
28
27
|
def initialize(options = {}); end
|
|
29
|
-
|
|
28
|
+
|
|
30
29
|
# default prompt object implementation. More sophisticated implemenetations
|
|
31
30
|
# might implement caching.
|
|
32
31
|
class Prompter
|
|
@@ -36,22 +35,22 @@ module Net
|
|
|
36
35
|
$stdout.puts(info[:instruction]) unless info[:instruction].empty?
|
|
37
36
|
end
|
|
38
37
|
end
|
|
39
|
-
|
|
38
|
+
|
|
40
39
|
# ask input from user, a prompter might ask for multiple inputs
|
|
41
40
|
# (like user and password) in a single session.
|
|
42
|
-
def ask(prompt, echo=true)
|
|
41
|
+
def ask(prompt, echo = true)
|
|
43
42
|
$stdout.print(prompt)
|
|
44
43
|
$stdout.flush
|
|
45
44
|
ret = $stdin.noecho(&:gets).chomp
|
|
46
45
|
$stdout.print("\n")
|
|
47
46
|
ret
|
|
48
47
|
end
|
|
49
|
-
|
|
48
|
+
|
|
50
49
|
# success method will be called when the password was accepted
|
|
51
50
|
# It's a good time to save password asked to a cache.
|
|
52
51
|
def success; end
|
|
53
52
|
end
|
|
54
|
-
|
|
53
|
+
|
|
55
54
|
# start password session. Multiple questions might be asked multiple times
|
|
56
55
|
# on the returned object. Info hash tries to uniquely identify the password
|
|
57
56
|
# session, so caching implementations can save passwords properly.
|
|
@@ -59,6 +58,5 @@ module Net
|
|
|
59
58
|
Prompter.new(info)
|
|
60
59
|
end
|
|
61
60
|
end
|
|
62
|
-
|
|
63
61
|
end
|
|
64
62
|
end
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
require 'socket'
|
|
2
2
|
require 'rubygems'
|
|
3
3
|
require 'net/ssh/proxy/errors'
|
|
4
|
-
require 'net/ssh/ruby_compat'
|
|
5
4
|
|
|
6
5
|
module Net
|
|
7
6
|
module SSH
|
|
8
7
|
module Proxy
|
|
9
|
-
|
|
10
8
|
# An implementation of a command proxy. To use it, instantiate it,
|
|
11
9
|
# then pass the instantiated object via the :proxy key to
|
|
12
10
|
# Net::SSH.start:
|
|
@@ -106,6 +104,7 @@ module Net
|
|
|
106
104
|
if IO.select([self], nil, [self], timeout_in_seconds) == nil
|
|
107
105
|
raise "Unexpected spurious read wakeup"
|
|
108
106
|
end
|
|
107
|
+
|
|
109
108
|
retry
|
|
110
109
|
end
|
|
111
110
|
result
|
data/lib/net/ssh/proxy/errors.rb
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
require 'net/ssh/errors'
|
|
2
2
|
|
|
3
|
-
module Net
|
|
4
|
-
module SSH
|
|
3
|
+
module Net
|
|
4
|
+
module SSH
|
|
5
5
|
module Proxy
|
|
6
|
-
|
|
7
6
|
# A general exception class for all Proxy errors.
|
|
8
7
|
class Error < Net::SSH::Exception; end
|
|
9
8
|
|
|
@@ -12,7 +11,6 @@ module Net
|
|
|
12
11
|
|
|
13
12
|
# Used when the server doesn't recognize the user's credentials.
|
|
14
13
|
class UnauthorizedError < Error; end
|
|
15
|
-
|
|
16
14
|
end
|
|
17
15
|
end
|
|
18
16
|
end
|
data/lib/net/ssh/proxy/http.rb
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
require 'socket'
|
|
2
2
|
require 'net/ssh/proxy/errors'
|
|
3
3
|
|
|
4
|
-
module Net
|
|
5
|
-
module SSH
|
|
4
|
+
module Net
|
|
5
|
+
module SSH
|
|
6
6
|
module Proxy
|
|
7
|
-
|
|
8
7
|
# An implementation of an HTTP proxy. To use it, instantiate it, then
|
|
9
8
|
# pass the instantiated object via the :proxy key to Net::SSH.start:
|
|
10
9
|
#
|
|
@@ -26,14 +25,14 @@ module Net
|
|
|
26
25
|
class HTTP
|
|
27
26
|
# The hostname or IP address of the HTTP proxy.
|
|
28
27
|
attr_reader :proxy_host
|
|
29
|
-
|
|
28
|
+
|
|
30
29
|
# The port number of the proxy.
|
|
31
30
|
attr_reader :proxy_port
|
|
32
|
-
|
|
31
|
+
|
|
33
32
|
# The map of additional options that were given to the object at
|
|
34
33
|
# initialization.
|
|
35
34
|
attr_reader :options
|
|
36
|
-
|
|
35
|
+
|
|
37
36
|
# Create a new socket factory that tunnels via the given host and
|
|
38
37
|
# port. The +options+ parameter is a hash of additional settings that
|
|
39
38
|
# can be used to tweak this proxy connection. Specifically, the following
|
|
@@ -41,52 +40,52 @@ module Net
|
|
|
41
40
|
#
|
|
42
41
|
# * :user => the user name to use when authenticating to the proxy
|
|
43
42
|
# * :password => the password to use when authenticating
|
|
44
|
-
def initialize(proxy_host, proxy_port=80, options={})
|
|
43
|
+
def initialize(proxy_host, proxy_port = 80, options = {})
|
|
45
44
|
@proxy_host = proxy_host
|
|
46
45
|
@proxy_port = proxy_port
|
|
47
46
|
@options = options
|
|
48
47
|
end
|
|
49
|
-
|
|
48
|
+
|
|
50
49
|
# Return a new socket connected to the given host and port via the
|
|
51
50
|
# proxy that was requested when the socket factory was instantiated.
|
|
52
51
|
def open(host, port, connection_options)
|
|
53
52
|
socket = establish_connection(connection_options[:timeout])
|
|
54
53
|
socket.write "CONNECT #{host}:#{port} HTTP/1.1\r\n"
|
|
55
54
|
socket.write "Host: #{host}:#{port}\r\n"
|
|
56
|
-
|
|
55
|
+
|
|
57
56
|
if options[:user]
|
|
58
57
|
credentials = ["#{options[:user]}:#{options[:password]}"].pack("m*").gsub(/\s/, "")
|
|
59
58
|
socket.write "Proxy-Authorization: Basic #{credentials}\r\n"
|
|
60
59
|
end
|
|
61
|
-
|
|
60
|
+
|
|
62
61
|
socket.write "\r\n"
|
|
63
|
-
|
|
62
|
+
|
|
64
63
|
resp = parse_response(socket)
|
|
65
|
-
|
|
64
|
+
|
|
66
65
|
return socket if resp[:code] == 200
|
|
67
|
-
|
|
66
|
+
|
|
68
67
|
socket.close
|
|
69
68
|
raise ConnectError, resp.inspect
|
|
70
69
|
end
|
|
71
|
-
|
|
70
|
+
|
|
72
71
|
protected
|
|
73
|
-
|
|
72
|
+
|
|
74
73
|
def establish_connection(connect_timeout)
|
|
75
74
|
Socket.tcp(proxy_host, proxy_port, nil, nil,
|
|
76
75
|
connect_timeout: connect_timeout)
|
|
77
76
|
end
|
|
78
|
-
|
|
77
|
+
|
|
79
78
|
def parse_response(socket)
|
|
80
79
|
version, code, reason = socket.gets.chomp.split(/ /, 3)
|
|
81
80
|
headers = {}
|
|
82
|
-
|
|
81
|
+
|
|
83
82
|
while (line = socket.gets) && (line.chomp! != "")
|
|
84
83
|
name, value = line.split(/:/, 2)
|
|
85
84
|
headers[name.strip] = value.strip
|
|
86
85
|
end
|
|
87
|
-
|
|
86
|
+
|
|
88
87
|
body = socket.read(headers["Content-Length"].to_i) if headers["Content-Length"]
|
|
89
|
-
|
|
88
|
+
|
|
90
89
|
return { version: version,
|
|
91
90
|
code: code.to_i,
|
|
92
91
|
reason: reason,
|
|
@@ -94,7 +93,6 @@ module Net
|
|
|
94
93
|
body: body }
|
|
95
94
|
end
|
|
96
95
|
end
|
|
97
|
-
|
|
98
96
|
end
|
|
99
97
|
end
|
|
100
98
|
end
|
data/lib/net/ssh/proxy/https.rb
CHANGED
|
@@ -3,10 +3,9 @@ require 'openssl'
|
|
|
3
3
|
require 'net/ssh/proxy/errors'
|
|
4
4
|
require 'net/ssh/proxy/http'
|
|
5
5
|
|
|
6
|
-
module Net
|
|
7
|
-
module SSH
|
|
6
|
+
module Net
|
|
7
|
+
module SSH
|
|
8
8
|
module Proxy
|
|
9
|
-
|
|
10
9
|
# A specialization of the HTTP proxy which encrypts the whole connection
|
|
11
10
|
# using OpenSSL. This has the advantage that proxy authentication
|
|
12
11
|
# information is not sent in plaintext.
|
|
@@ -17,27 +16,27 @@ module Net
|
|
|
17
16
|
# taken by Net::SSH::Proxy::HTTP it supports:
|
|
18
17
|
#
|
|
19
18
|
# * :ssl_context => the SSL configuration to use for the connection
|
|
20
|
-
def initialize(proxy_host, proxy_port=80, options={})
|
|
19
|
+
def initialize(proxy_host, proxy_port = 80, options = {})
|
|
21
20
|
@ssl_context = options.delete(:ssl_context) ||
|
|
22
21
|
OpenSSL::SSL::SSLContext.new
|
|
23
22
|
super(proxy_host, proxy_port, options)
|
|
24
23
|
end
|
|
25
|
-
|
|
24
|
+
|
|
26
25
|
protected
|
|
27
|
-
|
|
26
|
+
|
|
28
27
|
# Shim to make OpenSSL::SSL::SSLSocket behave like a regular TCPSocket
|
|
29
28
|
# for all intents and purposes of Net::SSH::BufferedIo
|
|
30
29
|
module SSLSocketCompatibility
|
|
31
|
-
def self.extended(object)
|
|
30
|
+
def self.extended(object) # :nodoc:
|
|
32
31
|
object.define_singleton_method(:recv, object.method(:sysread))
|
|
33
32
|
object.sync_close = true
|
|
34
33
|
end
|
|
35
|
-
|
|
34
|
+
|
|
36
35
|
def send(data, _opts)
|
|
37
36
|
syswrite(data)
|
|
38
37
|
end
|
|
39
38
|
end
|
|
40
|
-
|
|
39
|
+
|
|
41
40
|
def establish_connection(connect_timeout)
|
|
42
41
|
plain_socket = super(connect_timeout)
|
|
43
42
|
OpenSSL::SSL::SSLSocket.new(plain_socket, @ssl_context).tap do |socket|
|
|
@@ -46,7 +45,6 @@ module Net
|
|
|
46
45
|
end
|
|
47
46
|
end
|
|
48
47
|
end
|
|
49
|
-
|
|
50
48
|
end
|
|
51
49
|
end
|
|
52
50
|
end
|
data/lib/net/ssh/proxy/jump.rb
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
require 'uri'
|
|
2
2
|
require 'net/ssh/proxy/command'
|
|
3
3
|
|
|
4
|
-
module Net
|
|
5
|
-
module SSH
|
|
4
|
+
module Net
|
|
5
|
+
module SSH
|
|
6
6
|
module Proxy
|
|
7
|
-
|
|
8
7
|
# An implementation of a jump proxy. To use it, instantiate it,
|
|
9
8
|
# then pass the instantiated object via the :proxy key to
|
|
10
9
|
# Net::SSH.start:
|
|
@@ -18,39 +17,38 @@ module Net
|
|
|
18
17
|
class Jump < Command
|
|
19
18
|
# The jump proxies
|
|
20
19
|
attr_reader :jump_proxies
|
|
21
|
-
|
|
20
|
+
|
|
22
21
|
# Create a new socket factory that tunnels via multiple jump proxes as
|
|
23
22
|
# [user@]host[:port].
|
|
24
23
|
def initialize(jump_proxies)
|
|
25
24
|
@jump_proxies = jump_proxies
|
|
26
25
|
end
|
|
27
|
-
|
|
26
|
+
|
|
28
27
|
# Return a new socket connected to the given host and port via the jump
|
|
29
28
|
# proxy that was requested when the socket factory was instantiated.
|
|
30
29
|
def open(host, port, connection_options = nil)
|
|
31
30
|
build_proxy_command_equivalent(connection_options)
|
|
32
31
|
super
|
|
33
32
|
end
|
|
34
|
-
|
|
33
|
+
|
|
35
34
|
# We cannot build the ProxyCommand template until we know if the :config
|
|
36
35
|
# option was specified during `Net::SSH.start`.
|
|
37
36
|
def build_proxy_command_equivalent(connection_options = nil)
|
|
38
37
|
first_jump, extra_jumps = jump_proxies.split(",", 2)
|
|
39
38
|
config = connection_options && connection_options[:config]
|
|
40
39
|
uri = URI.parse("ssh://#{first_jump}")
|
|
41
|
-
|
|
42
|
-
template = "ssh"
|
|
40
|
+
|
|
41
|
+
template = "ssh".dup
|
|
43
42
|
template << " -l #{uri.user}" if uri.user
|
|
44
43
|
template << " -p #{uri.port}" if uri.port
|
|
45
44
|
template << " -J #{extra_jumps}" if extra_jumps
|
|
46
45
|
template << " -F #{config}" if config != true && config
|
|
47
46
|
template << " -W %h:%p "
|
|
48
47
|
template << uri.host
|
|
49
|
-
|
|
48
|
+
|
|
50
49
|
@command_line_template = template
|
|
51
50
|
end
|
|
52
51
|
end
|
|
53
|
-
|
|
54
52
|
end
|
|
55
53
|
end
|
|
56
54
|
end
|
data/lib/net/ssh/proxy/socks4.rb
CHANGED
|
@@ -6,7 +6,6 @@ require 'net/ssh/proxy/errors'
|
|
|
6
6
|
module Net
|
|
7
7
|
module SSH
|
|
8
8
|
module Proxy
|
|
9
|
-
|
|
10
9
|
# An implementation of a SOCKS4 proxy. To use it, instantiate it, then
|
|
11
10
|
# pass the instantiated object via the :proxy key to Net::SSH.start:
|
|
12
11
|
#
|
|
@@ -38,7 +37,7 @@ module Net
|
|
|
38
37
|
# Create a new proxy connection to the given proxy host and port.
|
|
39
38
|
# Optionally, a :user key may be given to identify the username
|
|
40
39
|
# with which to authenticate.
|
|
41
|
-
def initialize(proxy_host, proxy_port=1080, options={})
|
|
40
|
+
def initialize(proxy_host, proxy_port = 1080, options = {})
|
|
42
41
|
@proxy_host = proxy_host
|
|
43
42
|
@proxy_port = proxy_port
|
|
44
43
|
@options = options
|
|
@@ -50,7 +49,7 @@ module Net
|
|
|
50
49
|
socket = Socket.tcp(proxy_host, proxy_port, nil, nil,
|
|
51
50
|
connect_timeout: connection_options[:timeout])
|
|
52
51
|
ip_addr = IPAddr.new(Resolv.getaddress(host))
|
|
53
|
-
|
|
52
|
+
|
|
54
53
|
packet = [VERSION, CONNECT, port.to_i, ip_addr.to_i, options[:user]].pack("CCnNZ*")
|
|
55
54
|
socket.send packet, 0
|
|
56
55
|
|
|
@@ -63,7 +62,6 @@ module Net
|
|
|
63
62
|
return socket
|
|
64
63
|
end
|
|
65
64
|
end
|
|
66
|
-
|
|
67
65
|
end
|
|
68
66
|
end
|
|
69
67
|
end
|
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
|