net-ssh 5.0.0.beta1 → 5.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
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