net-ssh 5.0.0.beta1 → 5.0.0.beta2

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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.rubocop_todo.yml +98 -258
  5. data/CHANGES.txt +8 -0
  6. data/Gemfile +1 -3
  7. data/Rakefile +37 -39
  8. data/lib/net/ssh.rb +26 -25
  9. data/lib/net/ssh/authentication/agent.rb +228 -225
  10. data/lib/net/ssh/authentication/certificate.rb +166 -164
  11. data/lib/net/ssh/authentication/constants.rb +17 -14
  12. data/lib/net/ssh/authentication/ed25519.rb +107 -104
  13. data/lib/net/ssh/authentication/ed25519_loader.rb +32 -28
  14. data/lib/net/ssh/authentication/key_manager.rb +5 -3
  15. data/lib/net/ssh/authentication/methods/abstract.rb +53 -47
  16. data/lib/net/ssh/authentication/methods/hostbased.rb +32 -33
  17. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +2 -4
  18. data/lib/net/ssh/authentication/methods/none.rb +10 -10
  19. data/lib/net/ssh/authentication/methods/password.rb +13 -13
  20. data/lib/net/ssh/authentication/methods/publickey.rb +54 -55
  21. data/lib/net/ssh/authentication/pageant.rb +468 -465
  22. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +44 -0
  23. data/lib/net/ssh/authentication/session.rb +127 -123
  24. data/lib/net/ssh/buffer.rb +305 -303
  25. data/lib/net/ssh/buffered_io.rb +163 -162
  26. data/lib/net/ssh/config.rb +230 -227
  27. data/lib/net/ssh/connection/channel.rb +659 -654
  28. data/lib/net/ssh/connection/constants.rb +30 -26
  29. data/lib/net/ssh/connection/event_loop.rb +108 -104
  30. data/lib/net/ssh/connection/keepalive.rb +54 -50
  31. data/lib/net/ssh/connection/session.rb +677 -678
  32. data/lib/net/ssh/connection/term.rb +180 -176
  33. data/lib/net/ssh/errors.rb +101 -99
  34. data/lib/net/ssh/key_factory.rb +108 -108
  35. data/lib/net/ssh/known_hosts.rb +148 -154
  36. data/lib/net/ssh/loggable.rb +56 -54
  37. data/lib/net/ssh/packet.rb +82 -78
  38. data/lib/net/ssh/prompt.rb +55 -53
  39. data/lib/net/ssh/proxy/command.rb +103 -102
  40. data/lib/net/ssh/proxy/errors.rb +12 -8
  41. data/lib/net/ssh/proxy/http.rb +92 -91
  42. data/lib/net/ssh/proxy/https.rb +42 -39
  43. data/lib/net/ssh/proxy/jump.rb +50 -47
  44. data/lib/net/ssh/proxy/socks4.rb +0 -2
  45. data/lib/net/ssh/proxy/socks5.rb +11 -11
  46. data/lib/net/ssh/ruby_compat.rb +1 -0
  47. data/lib/net/ssh/service/forward.rb +364 -362
  48. data/lib/net/ssh/test.rb +85 -83
  49. data/lib/net/ssh/test/channel.rb +146 -142
  50. data/lib/net/ssh/test/extensions.rb +148 -146
  51. data/lib/net/ssh/test/kex.rb +35 -31
  52. data/lib/net/ssh/test/local_packet.rb +48 -44
  53. data/lib/net/ssh/test/packet.rb +87 -84
  54. data/lib/net/ssh/test/remote_packet.rb +35 -31
  55. data/lib/net/ssh/test/script.rb +173 -171
  56. data/lib/net/ssh/test/socket.rb +59 -55
  57. data/lib/net/ssh/transport/algorithms.rb +413 -412
  58. data/lib/net/ssh/transport/cipher_factory.rb +108 -105
  59. data/lib/net/ssh/transport/constants.rb +35 -31
  60. data/lib/net/ssh/transport/ctr.rb +1 -1
  61. data/lib/net/ssh/transport/hmac.rb +1 -1
  62. data/lib/net/ssh/transport/hmac/abstract.rb +67 -64
  63. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +1 -1
  64. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +1 -1
  65. data/lib/net/ssh/transport/identity_cipher.rb +55 -51
  66. data/lib/net/ssh/transport/kex.rb +2 -4
  67. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +47 -40
  68. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +201 -197
  69. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -56
  70. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +94 -87
  71. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +17 -10
  72. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +17 -10
  73. data/lib/net/ssh/transport/key_expander.rb +29 -25
  74. data/lib/net/ssh/transport/openssl.rb +17 -30
  75. data/lib/net/ssh/transport/packet_stream.rb +193 -192
  76. data/lib/net/ssh/transport/server_version.rb +64 -66
  77. data/lib/net/ssh/transport/session.rb +286 -284
  78. data/lib/net/ssh/transport/state.rb +198 -196
  79. data/lib/net/ssh/verifiers/lenient.rb +29 -25
  80. data/lib/net/ssh/verifiers/null.rb +13 -9
  81. data/lib/net/ssh/verifiers/secure.rb +45 -45
  82. data/lib/net/ssh/verifiers/strict.rb +20 -16
  83. data/lib/net/ssh/version.rb +55 -53
  84. data/net-ssh.gemspec +4 -4
  85. data/support/ssh_tunnel_bug.rb +2 -2
  86. metadata +25 -24
  87. metadata.gz.sig +0 -0
@@ -1,14 +1,18 @@
1
1
  require 'net/ssh/errors'
2
2
 
3
- module Net; module SSH; module Proxy
3
+ module Net
4
+ module SSH
5
+ module Proxy
4
6
 
5
- # A general exception class for all Proxy errors.
6
- class Error < Net::SSH::Exception; end
7
+ # A general exception class for all Proxy errors.
8
+ class Error < Net::SSH::Exception; end
7
9
 
8
- # Used for reporting proxy connection errors.
9
- class ConnectError < Error; end
10
+ # Used for reporting proxy connection errors.
11
+ class ConnectError < Error; end
10
12
 
11
- # Used when the server doesn't recognize the user's credentials.
12
- class UnauthorizedError < Error; end
13
+ # Used when the server doesn't recognize the user's credentials.
14
+ class UnauthorizedError < Error; end
13
15
 
14
- end; end; end
16
+ end
17
+ end
18
+ end
@@ -1,98 +1,99 @@
1
1
  require 'socket'
2
2
  require 'net/ssh/proxy/errors'
3
3
 
4
- module Net; module SSH; module Proxy
5
-
6
- # An implementation of an HTTP proxy. To use it, instantiate it, then
7
- # pass the instantiated object via the :proxy key to Net::SSH.start:
8
- #
9
- # require 'net/ssh/proxy/http'
10
- #
11
- # proxy = Net::SSH::Proxy::HTTP.new('proxy_host', proxy_port)
12
- # Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
13
- # ...
14
- # end
15
- #
16
- # If the proxy requires authentication, you can pass :user and :password
17
- # to the proxy's constructor:
18
- #
19
- # proxy = Net::SSH::Proxy::HTTP.new('proxy_host', proxy_port,
20
- # :user => "user", :password => "password")
21
- #
22
- # Note that HTTP digest authentication is not supported; Basic only at
23
- # this point.
24
- class HTTP
25
-
26
- # The hostname or IP address of the HTTP proxy.
27
- attr_reader :proxy_host
28
-
29
- # The port number of the proxy.
30
- attr_reader :proxy_port
31
-
32
- # The map of additional options that were given to the object at
33
- # initialization.
34
- attr_reader :options
35
-
36
- # Create a new socket factory that tunnels via the given host and
37
- # port. The +options+ parameter is a hash of additional settings that
38
- # can be used to tweak this proxy connection. Specifically, the following
39
- # options are supported:
40
- #
41
- # * :user => the user name to use when authenticating to the proxy
42
- # * :password => the password to use when authenticating
43
- def initialize(proxy_host, proxy_port=80, options={})
44
- @proxy_host = proxy_host
45
- @proxy_port = proxy_port
46
- @options = options
47
- end
48
-
49
- # Return a new socket connected to the given host and port via the
50
- # proxy that was requested when the socket factory was instantiated.
51
- def open(host, port, connection_options)
52
- socket = establish_connection(connection_options[:timeout])
53
- socket.write "CONNECT #{host}:#{port} HTTP/1.0\r\n"
54
-
55
- if options[:user]
56
- credentials = ["#{options[:user]}:#{options[:password]}"].pack("m*").gsub(/\s/, "")
57
- socket.write "Proxy-Authorization: Basic #{credentials}\r\n"
58
- end
59
-
60
- socket.write "\r\n"
61
-
62
- resp = parse_response(socket)
63
-
64
- return socket if resp[:code] == 200
65
-
66
- socket.close
67
- raise ConnectError, resp.inspect
68
- end
69
-
70
- protected
71
-
72
- def establish_connection(connect_timeout)
73
- Socket.tcp(proxy_host, proxy_port, nil, nil,
74
- connect_timeout: connect_timeout)
75
- end
76
-
77
- def parse_response(socket)
78
- version, code, reason = socket.gets.chomp.split(/ /, 3)
79
- headers = {}
80
-
81
- while (line = socket.gets) && (line.chomp! != "")
82
- name, value = line.split(/:/, 2)
83
- headers[name.strip] = value.strip
4
+ module Net
5
+ module SSH
6
+ module Proxy
7
+
8
+ # An implementation of an HTTP proxy. To use it, instantiate it, then
9
+ # pass the instantiated object via the :proxy key to Net::SSH.start:
10
+ #
11
+ # require 'net/ssh/proxy/http'
12
+ #
13
+ # proxy = Net::SSH::Proxy::HTTP.new('proxy_host', proxy_port)
14
+ # Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
15
+ # ...
16
+ # end
17
+ #
18
+ # If the proxy requires authentication, you can pass :user and :password
19
+ # to the proxy's constructor:
20
+ #
21
+ # proxy = Net::SSH::Proxy::HTTP.new('proxy_host', proxy_port,
22
+ # :user => "user", :password => "password")
23
+ #
24
+ # Note that HTTP digest authentication is not supported; Basic only at
25
+ # this point.
26
+ class HTTP
27
+ # The hostname or IP address of the HTTP proxy.
28
+ attr_reader :proxy_host
29
+
30
+ # The port number of the proxy.
31
+ attr_reader :proxy_port
32
+
33
+ # The map of additional options that were given to the object at
34
+ # initialization.
35
+ attr_reader :options
36
+
37
+ # Create a new socket factory that tunnels via the given host and
38
+ # port. The +options+ parameter is a hash of additional settings that
39
+ # can be used to tweak this proxy connection. Specifically, the following
40
+ # options are supported:
41
+ #
42
+ # * :user => the user name to use when authenticating to the proxy
43
+ # * :password => the password to use when authenticating
44
+ def initialize(proxy_host, proxy_port=80, options={})
45
+ @proxy_host = proxy_host
46
+ @proxy_port = proxy_port
47
+ @options = options
84
48
  end
85
-
86
- if headers["Content-Length"]
87
- body = socket.read(headers["Content-Length"].to_i)
49
+
50
+ # Return a new socket connected to the given host and port via the
51
+ # proxy that was requested when the socket factory was instantiated.
52
+ def open(host, port, connection_options)
53
+ socket = establish_connection(connection_options[:timeout])
54
+ socket.write "CONNECT #{host}:#{port} HTTP/1.0\r\n"
55
+
56
+ if options[:user]
57
+ credentials = ["#{options[:user]}:#{options[:password]}"].pack("m*").gsub(/\s/, "")
58
+ socket.write "Proxy-Authorization: Basic #{credentials}\r\n"
59
+ end
60
+
61
+ socket.write "\r\n"
62
+
63
+ resp = parse_response(socket)
64
+
65
+ return socket if resp[:code] == 200
66
+
67
+ socket.close
68
+ raise ConnectError, resp.inspect
69
+ end
70
+
71
+ protected
72
+
73
+ def establish_connection(connect_timeout)
74
+ Socket.tcp(proxy_host, proxy_port, nil, nil,
75
+ connect_timeout: connect_timeout)
76
+ end
77
+
78
+ def parse_response(socket)
79
+ version, code, reason = socket.gets.chomp.split(/ /, 3)
80
+ headers = {}
81
+
82
+ while (line = socket.gets) && (line.chomp! != "")
83
+ name, value = line.split(/:/, 2)
84
+ headers[name.strip] = value.strip
85
+ end
86
+
87
+ body = socket.read(headers["Content-Length"].to_i) if headers["Content-Length"]
88
+
89
+ return { version: version,
90
+ code: code.to_i,
91
+ reason: reason,
92
+ headers: headers,
93
+ body: body }
88
94
  end
89
-
90
- return { version: version,
91
- code: code.to_i,
92
- reason: reason,
93
- headers: headers,
94
- body: body }
95
95
  end
96
- end
97
96
 
98
- end; end; end
97
+ end
98
+ end
99
+ end
@@ -3,47 +3,50 @@ require 'openssl'
3
3
  require 'net/ssh/proxy/errors'
4
4
  require 'net/ssh/proxy/http'
5
5
 
6
- module Net; module SSH; module Proxy
7
-
8
- # A specialization of the HTTP proxy which encrypts the whole connection
9
- # using OpenSSL. This has the advantage that proxy authentication
10
- # information is not sent in plaintext.
11
- class HTTPS < HTTP
12
-
13
- # Create a new socket factory that tunnels via the given host and
14
- # port. The +options+ parameter is a hash of additional settings that
15
- # can be used to tweak this proxy connection. In addition to the options
16
- # taken by Net::SSH::Proxy::HTTP it supports:
17
- #
18
- # * :ssl_context => the SSL configuration to use for the connection
19
- def initialize(proxy_host, proxy_port=80, options={})
20
- @ssl_context = options.delete(:ssl_context) ||
21
- OpenSSL::SSL::SSLContext.new
22
- super(proxy_host, proxy_port, options)
23
- end
24
-
25
- protected
26
-
27
- # Shim to make OpenSSL::SSL::SSLSocket behave like a regular TCPSocket
28
- # for all intents and purposes of Net::SSH::BufferedIo
29
- module SSLSocketCompatibility
30
- def self.extended(object) #:nodoc:
31
- object.define_singleton_method(:recv, object.method(:sysread))
32
- object.sync_close = true
6
+ module Net
7
+ module SSH
8
+ module Proxy
9
+
10
+ # A specialization of the HTTP proxy which encrypts the whole connection
11
+ # using OpenSSL. This has the advantage that proxy authentication
12
+ # information is not sent in plaintext.
13
+ class HTTPS < HTTP
14
+ # Create a new socket factory that tunnels via the given host and
15
+ # port. The +options+ parameter is a hash of additional settings that
16
+ # can be used to tweak this proxy connection. In addition to the options
17
+ # taken by Net::SSH::Proxy::HTTP it supports:
18
+ #
19
+ # * :ssl_context => the SSL configuration to use for the connection
20
+ def initialize(proxy_host, proxy_port=80, options={})
21
+ @ssl_context = options.delete(:ssl_context) ||
22
+ OpenSSL::SSL::SSLContext.new
23
+ super(proxy_host, proxy_port, options)
33
24
  end
34
-
35
- def send(data, _opts)
36
- syswrite(data)
25
+
26
+ protected
27
+
28
+ # Shim to make OpenSSL::SSL::SSLSocket behave like a regular TCPSocket
29
+ # for all intents and purposes of Net::SSH::BufferedIo
30
+ module SSLSocketCompatibility
31
+ def self.extended(object) #:nodoc:
32
+ object.define_singleton_method(:recv, object.method(:sysread))
33
+ object.sync_close = true
34
+ end
35
+
36
+ def send(data, _opts)
37
+ syswrite(data)
38
+ end
37
39
  end
38
- end
39
-
40
- def establish_connection(connect_timeout)
41
- plain_socket = super(connect_timeout)
42
- OpenSSL::SSL::SSLSocket.new(plain_socket, @ssl_context).tap do |socket|
43
- socket.extend(SSLSocketCompatibility)
44
- socket.connect
40
+
41
+ def establish_connection(connect_timeout)
42
+ plain_socket = super(connect_timeout)
43
+ OpenSSL::SSL::SSLSocket.new(plain_socket, @ssl_context).tap do |socket|
44
+ socket.extend(SSLSocketCompatibility)
45
+ socket.connect
46
+ end
45
47
  end
46
48
  end
47
- end
48
49
 
49
- end; end; end
50
+ end
51
+ end
52
+ end
@@ -1,53 +1,56 @@
1
1
  require 'uri'
2
2
  require 'net/ssh/proxy/command'
3
3
 
4
- module Net; module SSH; module Proxy
4
+ module Net
5
+ module SSH
6
+ module Proxy
7
+
8
+ # An implementation of a jump proxy. To use it, instantiate it,
9
+ # then pass the instantiated object via the :proxy key to
10
+ # Net::SSH.start:
11
+ #
12
+ # require 'net/ssh/proxy/jump'
13
+ #
14
+ # proxy = Net::SSH::Proxy::Jump.new('user@proxy')
15
+ # Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
16
+ # ...
17
+ # end
18
+ class Jump < Command
19
+ # The jump proxies
20
+ attr_reader :jump_proxies
21
+
22
+ # Create a new socket factory that tunnels via multiple jump proxes as
23
+ # [user@]host[:port].
24
+ def initialize(jump_proxies)
25
+ @jump_proxies = jump_proxies
26
+ end
27
+
28
+ # Return a new socket connected to the given host and port via the jump
29
+ # proxy that was requested when the socket factory was instantiated.
30
+ def open(host, port, connection_options = nil)
31
+ build_proxy_command_equivalent(connection_options)
32
+ super
33
+ end
34
+
35
+ # We cannot build the ProxyCommand template until we know if the :config
36
+ # option was specified during `Net::SSH.start`.
37
+ def build_proxy_command_equivalent(connection_options = nil)
38
+ first_jump, extra_jumps = jump_proxies.split(",", 2)
39
+ config = connection_options && connection_options[:config]
40
+ uri = URI.parse("ssh://#{first_jump}")
41
+
42
+ template = "ssh"
43
+ template << " -l #{uri.user}" if uri.user
44
+ template << " -p #{uri.port}" if uri.port
45
+ template << " -J #{extra_jumps}" if extra_jumps
46
+ template << " -F #{config}" if config != true && config
47
+ template << " -W %h:%p "
48
+ template << uri.host
49
+
50
+ @command_line_template = template
51
+ end
52
+ end
5
53
 
6
- # An implementation of a jump proxy. To use it, instantiate it,
7
- # then pass the instantiated object via the :proxy key to
8
- # Net::SSH.start:
9
- #
10
- # require 'net/ssh/proxy/jump'
11
- #
12
- # proxy = Net::SSH::Proxy::Jump.new('user@proxy')
13
- # Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
14
- # ...
15
- # end
16
- class Jump < Command
17
-
18
- # The jump proxies
19
- attr_reader :jump_proxies
20
-
21
- # Create a new socket factory that tunnels via multiple jump proxes as
22
- # [user@]host[:port].
23
- def initialize(jump_proxies)
24
- @jump_proxies = jump_proxies
25
- end
26
-
27
- # Return a new socket connected to the given host and port via the jump
28
- # proxy that was requested when the socket factory was instantiated.
29
- def open(host, port, connection_options = nil)
30
- build_proxy_command_equivalent(connection_options)
31
- super
32
- end
33
-
34
- # We cannot build the ProxyCommand template until we know if the :config
35
- # option was specified during `Net::SSH.start`.
36
- def build_proxy_command_equivalent(connection_options = nil)
37
- first_jump, extra_jumps = jump_proxies.split(",", 2)
38
- config = connection_options && connection_options[:config]
39
- uri = URI.parse("ssh://#{first_jump}")
40
-
41
- template = "ssh"
42
- template << " -l #{uri.user}" if uri.user
43
- template << " -p #{uri.port}" if uri.port
44
- template << " -J #{extra_jumps}" if extra_jumps
45
- template << " -F #{config}" if config != true && config
46
- template << " -W %h:%p "
47
- template << uri.host
48
-
49
- @command_line_template = template
50
54
  end
51
55
  end
52
-
53
- end; end; end
56
+ end
@@ -17,7 +17,6 @@ module Net
17
17
  # ...
18
18
  # end
19
19
  class SOCKS4
20
-
21
20
  # The SOCKS protocol version used by this class
22
21
  VERSION = 4
23
22
 
@@ -63,7 +62,6 @@ module Net
63
62
 
64
63
  return socket
65
64
  end
66
-
67
65
  end
68
66
 
69
67
  end
@@ -101,7 +101,7 @@ module Net
101
101
  address_type = socket.recv(1).getbyte(0)
102
102
  case address_type
103
103
  when 1
104
- socket.recv(4) # get four bytes for IPv4 address
104
+ socket.recv(4) # get four bytes for IPv4 address
105
105
  when 3
106
106
  len = socket.recv(1).getbyte(0)
107
107
  hostname = socket.recv(len)
@@ -123,19 +123,19 @@ module Net
123
123
 
124
124
  private
125
125
 
126
- # Simple username/password negotiation with the SOCKS5 server.
127
- def negotiate_password(socket)
128
- packet = [0x01, options[:user].length, options[:user],
129
- options[:password].length, options[:password]].pack("CCA*CA*")
130
- socket.send packet, 0
126
+ # Simple username/password negotiation with the SOCKS5 server.
127
+ def negotiate_password(socket)
128
+ packet = [0x01, options[:user].length, options[:user],
129
+ options[:password].length, options[:password]].pack("CCA*CA*")
130
+ socket.send packet, 0
131
131
 
132
- version, status = socket.recv(2).unpack("CC")
132
+ version, status = socket.recv(2).unpack("CC")
133
133
 
134
- if status != SUCCESS
135
- socket.close
136
- raise UnauthorizedError, "could not authorize user"
137
- end
134
+ if status != SUCCESS
135
+ socket.close
136
+ raise UnauthorizedError, "could not authorize user"
138
137
  end
138
+ end
139
139
  end
140
140
 
141
141
  end