net-ssh 5.0.2 → 7.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/config/rubocop_linter_action.yml +4 -0
  5. data/.github/workflows/ci-with-docker.yml +44 -0
  6. data/.github/workflows/ci.yml +87 -0
  7. data/.github/workflows/rubocop.yml +13 -0
  8. data/.gitignore +3 -0
  9. data/.rubocop.yml +19 -2
  10. data/.rubocop_todo.yml +623 -511
  11. data/CHANGES.txt +76 -0
  12. data/Dockerfile +27 -0
  13. data/Dockerfile.openssl3 +17 -0
  14. data/Gemfile +2 -0
  15. data/Gemfile.noed25519 +2 -0
  16. data/Manifest +0 -1
  17. data/README.md +293 -0
  18. data/Rakefile +6 -2
  19. data/appveyor.yml +4 -2
  20. data/docker-compose.yml +23 -0
  21. data/lib/net/ssh/authentication/agent.rb +36 -14
  22. data/lib/net/ssh/authentication/certificate.rb +19 -7
  23. data/lib/net/ssh/authentication/constants.rb +0 -1
  24. data/lib/net/ssh/authentication/ed25519.rb +83 -50
  25. data/lib/net/ssh/authentication/ed25519_loader.rb +5 -8
  26. data/lib/net/ssh/authentication/key_manager.rb +74 -33
  27. data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
  28. data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
  29. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +5 -3
  30. data/lib/net/ssh/authentication/methods/none.rb +6 -9
  31. data/lib/net/ssh/authentication/methods/password.rb +2 -3
  32. data/lib/net/ssh/authentication/methods/publickey.rb +58 -16
  33. data/lib/net/ssh/authentication/pageant.rb +97 -97
  34. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -3
  35. data/lib/net/ssh/authentication/session.rb +27 -23
  36. data/lib/net/ssh/buffer.rb +91 -40
  37. data/lib/net/ssh/buffered_io.rb +24 -26
  38. data/lib/net/ssh/config.rb +99 -53
  39. data/lib/net/ssh/connection/channel.rb +101 -87
  40. data/lib/net/ssh/connection/constants.rb +0 -4
  41. data/lib/net/ssh/connection/event_loop.rb +30 -25
  42. data/lib/net/ssh/connection/keepalive.rb +12 -12
  43. data/lib/net/ssh/connection/session.rb +115 -111
  44. data/lib/net/ssh/connection/term.rb +56 -58
  45. data/lib/net/ssh/errors.rb +12 -12
  46. data/lib/net/ssh/key_factory.rb +108 -22
  47. data/lib/net/ssh/known_hosts.rb +120 -36
  48. data/lib/net/ssh/loggable.rb +10 -11
  49. data/lib/net/ssh/packet.rb +1 -1
  50. data/lib/net/ssh/prompt.rb +9 -11
  51. data/lib/net/ssh/proxy/command.rb +1 -2
  52. data/lib/net/ssh/proxy/errors.rb +2 -4
  53. data/lib/net/ssh/proxy/http.rb +18 -20
  54. data/lib/net/ssh/proxy/https.rb +8 -10
  55. data/lib/net/ssh/proxy/jump.rb +8 -10
  56. data/lib/net/ssh/proxy/socks4.rb +2 -4
  57. data/lib/net/ssh/proxy/socks5.rb +3 -6
  58. data/lib/net/ssh/service/forward.rb +9 -8
  59. data/lib/net/ssh/test/channel.rb +24 -26
  60. data/lib/net/ssh/test/extensions.rb +37 -35
  61. data/lib/net/ssh/test/kex.rb +6 -8
  62. data/lib/net/ssh/test/local_packet.rb +0 -2
  63. data/lib/net/ssh/test/packet.rb +3 -3
  64. data/lib/net/ssh/test/remote_packet.rb +6 -8
  65. data/lib/net/ssh/test/script.rb +25 -27
  66. data/lib/net/ssh/test/socket.rb +12 -15
  67. data/lib/net/ssh/test.rb +12 -12
  68. data/lib/net/ssh/transport/algorithms.rb +177 -118
  69. data/lib/net/ssh/transport/cipher_factory.rb +34 -50
  70. data/lib/net/ssh/transport/constants.rb +13 -9
  71. data/lib/net/ssh/transport/ctr.rb +8 -14
  72. data/lib/net/ssh/transport/hmac/abstract.rb +20 -5
  73. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  74. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  75. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  76. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  77. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  78. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  79. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  80. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  81. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  82. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  83. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  84. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  85. data/lib/net/ssh/transport/hmac.rb +13 -11
  86. data/lib/net/ssh/transport/identity_cipher.rb +11 -13
  87. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  88. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  89. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  90. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +5 -19
  92. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  93. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +30 -139
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -8
  95. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  96. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +20 -81
  97. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +5 -4
  98. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +5 -4
  99. data/lib/net/ssh/transport/kex.rb +15 -10
  100. data/lib/net/ssh/transport/key_expander.rb +7 -8
  101. data/lib/net/ssh/transport/openssl.rb +149 -111
  102. data/lib/net/ssh/transport/packet_stream.rb +53 -22
  103. data/lib/net/ssh/transport/server_version.rb +17 -16
  104. data/lib/net/ssh/transport/session.rb +35 -11
  105. data/lib/net/ssh/transport/state.rb +44 -44
  106. data/lib/net/ssh/verifiers/accept_new.rb +7 -2
  107. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
  108. data/lib/net/ssh/verifiers/always.rb +10 -4
  109. data/lib/net/ssh/verifiers/never.rb +4 -2
  110. data/lib/net/ssh/version.rb +2 -2
  111. data/lib/net/ssh.rb +17 -9
  112. data/net-ssh-public_cert.pem +18 -19
  113. data/net-ssh.gemspec +9 -7
  114. data/support/ssh_tunnel_bug.rb +3 -3
  115. data.tar.gz.sig +0 -0
  116. metadata +65 -41
  117. metadata.gz.sig +0 -0
  118. data/.travis.yml +0 -52
  119. data/Gemfile.noed25519.lock +0 -41
  120. data/README.rdoc +0 -169
  121. data/lib/net/ssh/ruby_compat.rb +0 -13
  122. data/support/arcfour_check.rb +0 -20
@@ -1,10 +1,69 @@
1
1
  require 'strscan'
2
2
  require 'openssl'
3
3
  require 'base64'
4
+ require 'delegate'
4
5
  require 'net/ssh/buffer'
6
+ require 'net/ssh/authentication/ed25519_loader'
5
7
 
6
8
  module Net
7
9
  module SSH
10
+ module HostKeyEntries
11
+ # regular public key entry
12
+ class PubKey < Delegator
13
+ def initialize(key, comment: nil) # rubocop:disable Lint/MissingSuper
14
+ @key = key
15
+ @comment = comment
16
+ end
17
+
18
+ def ssh_type
19
+ @key.ssh_type
20
+ end
21
+
22
+ def ssh_types
23
+ [ssh_type]
24
+ end
25
+
26
+ def to_blob
27
+ @key.to_blob
28
+ end
29
+
30
+ def __getobj__
31
+ Kernel.warn("Calling Net::SSH::Buffer methods on HostKeyEntries PubKey is deprecated")
32
+ @key
33
+ end
34
+
35
+ def matches_key?(server_key)
36
+ @key.ssh_type == server_key.ssh_type && @key.to_blob == server_key.to_blob
37
+ end
38
+ end
39
+
40
+ # @cert-authority entry
41
+ class CertAuthority
42
+ def ssh_types
43
+ %w[
44
+ ecdsa-sha2-nistp256-cert-v01@openssh.com
45
+ ecdsa-sha2-nistp384-cert-v01@openssh.com
46
+ ecdsa-sha2-nistp521-cert-v01@openssh.com
47
+ ssh-ed25519-cert-v01@openssh.com
48
+ ssh-rsa-cert-v01@openssh.com
49
+ ssh-rsa-cert-v00@openssh.com
50
+ ]
51
+ end
52
+
53
+ def initialize(key, comment: nil)
54
+ @key = key
55
+ @comment = comment
56
+ end
57
+
58
+ def matches_key?(server_key)
59
+ if ssh_types.include?(server_key.ssh_type)
60
+ server_key.signature_valid? && (server_key.signature_key.to_blob == @key.to_blob)
61
+ else
62
+ false
63
+ end
64
+ end
65
+ end
66
+ end
8
67
 
9
68
  # Represents the result of a search in known hosts
10
69
  # see search_for
@@ -40,26 +99,24 @@ module Net
40
99
  # This is used internally by Net::SSH, and will never need to be used directly
41
100
  # by consumers of the library.
42
101
  class KnownHosts
43
- if defined?(OpenSSL::PKey::EC)
44
- SUPPORTED_TYPE = %w[ssh-rsa ssh-dss
45
- ecdsa-sha2-nistp256
46
- ecdsa-sha2-nistp384
47
- ecdsa-sha2-nistp521]
48
- else
49
- SUPPORTED_TYPE = %w[ssh-rsa ssh-dss]
50
- end
102
+ SUPPORTED_TYPE = %w[ssh-rsa ssh-dss
103
+ ecdsa-sha2-nistp256
104
+ ecdsa-sha2-nistp384
105
+ ecdsa-sha2-nistp521]
106
+
107
+ SUPPORTED_TYPE.push('ssh-ed25519') if Net::SSH::Authentication::ED25519Loader::LOADED
51
108
 
52
- class <<self
109
+ class << self
53
110
  # Searches all known host files (see KnownHosts.hostfiles) for all keys
54
111
  # of the given host. Returns an enumerable of keys found.
55
- def search_for(host, options={})
56
- HostKeys.new(search_in(hostfiles(options), host), host, self, options)
112
+ def search_for(host, options = {})
113
+ HostKeys.new(search_in(hostfiles(options), host, options), host, self, options)
57
114
  end
58
115
 
59
116
  # Search for all known keys for the given host, in every file given in
60
117
  # the +files+ array. Returns the list of keys.
61
- def search_in(files, host)
62
- files.flat_map { |file| KnownHosts.new(file).keys_for(host) }
118
+ def search_in(files, host, options = {})
119
+ files.flat_map { |file| KnownHosts.new(file).keys_for(host, options) }
63
120
  end
64
121
 
65
122
  # Looks in the given +options+ hash for the :user_known_hosts_file and
@@ -71,12 +128,14 @@ module Net
71
128
  #
72
129
  # If you only want the user known host files, you can pass :user as
73
130
  # the second option.
74
- def hostfiles(options, which=:all)
131
+ def hostfiles(options, which = :all)
75
132
  files = []
76
133
 
77
134
  files += Array(options[:user_known_hosts_file] || %w[~/.ssh/known_hosts ~/.ssh/known_hosts2]) if which == :all || which == :user
78
135
 
79
- files += Array(options[:global_known_hosts_file] || %w[/etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2]) if which == :all || which == :global
136
+ if which == :all || which == :global
137
+ files += Array(options[:global_known_hosts_file] || %w[/etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2])
138
+ end
80
139
 
81
140
  return files
82
141
  end
@@ -84,14 +143,12 @@ module Net
84
143
  # Looks in all user known host files (see KnownHosts.hostfiles) and tries to
85
144
  # add an entry for the given host and key to the first file it is able
86
145
  # to.
87
- def add(host, key, options={})
146
+ def add(host, key, options = {})
88
147
  hostfiles(options, :user).each do |file|
89
- begin
90
- KnownHosts.new(file).add(host, key)
91
- return
92
- rescue SystemCallError
93
- # try the next hostfile
94
- end
148
+ KnownHosts.new(file).add(host, key)
149
+ return
150
+ rescue SystemCallError
151
+ # try the next hostfile
95
152
  end
96
153
  end
97
154
  end
@@ -119,39 +176,66 @@ module Net
119
176
  # "[net.ssh.test]:5555"
120
177
  # "[1,2,3,4]:5555"
121
178
  # "[net.ssh.test]:5555,[1.2.3.4]:5555
122
- def keys_for(host)
179
+ def keys_for(host, options = {})
123
180
  keys = []
124
181
  return keys unless File.readable?(source)
125
182
 
126
183
  entries = host.split(/,/)
184
+ host_name = entries[0]
185
+ host_ip = entries[1]
127
186
 
128
187
  File.open(source) do |file|
129
- scanner = StringScanner.new("")
130
188
  file.each_line do |line|
131
- scanner.string = line
189
+ if line.start_with?('@')
190
+ marker, hosts, type, key_content, comment = line.split(' ')
191
+ else
192
+ marker = nil
193
+ hosts, type, key_content, comment = line.split(' ')
194
+ end
195
+
196
+ # Skip empty line or one that is commented
197
+ next if hosts.nil? || hosts.start_with?('#')
132
198
 
133
- scanner.skip(/\s*/)
134
- next if scanner.match?(/$|#/)
199
+ hostlist = hosts.split(',')
135
200
 
136
- hostlist = scanner.scan(/\S+/).split(/,/)
137
- found = entries.all? { |entry| hostlist.include?(entry) } ||
138
- known_host_hash?(hostlist, entries)
201
+ next unless SUPPORTED_TYPE.include?(type)
202
+
203
+ found = hostlist.any? { |pattern| match(host_name, pattern) } || known_host_hash?(hostlist, entries)
139
204
  next unless found
140
205
 
141
- scanner.skip(/\s*/)
142
- type = scanner.scan(/\S+/)
206
+ found = hostlist.include?(host_ip) if options[:check_host_ip] && entries.size > 1 && hostlist.size > 1
207
+ next unless found
143
208
 
144
- next unless SUPPORTED_TYPE.include?(type)
209
+ blob = key_content.unpack("m*").first
210
+ raw_key = Net::SSH::Buffer.new(blob).read_key
145
211
 
146
- scanner.skip(/\s*/)
147
- blob = scanner.rest.unpack("m*").first
148
- keys << Net::SSH::Buffer.new(blob).read_key
212
+ keys <<
213
+ if marker == "@cert-authority"
214
+ HostKeyEntries::CertAuthority.new(raw_key, comment: comment)
215
+ else
216
+ HostKeyEntries::PubKey.new(raw_key, comment: comment)
217
+ end
149
218
  end
150
219
  end
151
220
 
152
221
  keys
153
222
  end
154
223
 
224
+ def match(host, pattern)
225
+ if pattern.include?('*') || pattern.include?('?')
226
+ # see man 8 sshd for pattern details
227
+ pattern_regexp = pattern.split('*', -1).map do |x|
228
+ x.split('?', -1).map do |y|
229
+ Regexp.escape(y)
230
+ end.join('.')
231
+ end.join('.*')
232
+
233
+ host =~ Regexp.new("\\A#{pattern_regexp}\\z")
234
+ else
235
+ host == pattern
236
+ end
237
+ end
238
+
155
239
  # Indicates whether one of the entries matches an hostname that has been
156
240
  # stored as a HMAC-SHA1 hash in the known hosts.
157
241
  def known_host_hash?(hostlist, entries)
@@ -1,6 +1,5 @@
1
- module Net
1
+ module Net
2
2
  module SSH
3
-
4
3
  # A simple module to make logging easier to deal with. It assumes that the
5
4
  # logger instance (if not nil) quacks like a Logger object (in Ruby's
6
5
  # standard library). Although used primarily internally by Net::SSH, it
@@ -19,45 +18,45 @@ module Net
19
18
  # The logger instance that will be used to log messages. If nil, nothing
20
19
  # will be logged.
21
20
  attr_accessor :logger
22
-
21
+
23
22
  # Displays the result of yielding if the log level is Logger::DEBUG or
24
23
  # greater.
25
24
  def debug
26
25
  logger.add(Logger::DEBUG, nil, facility) { yield } if logger && logger.debug?
27
26
  end
28
-
27
+
29
28
  # Displays the result of yielding if the log level is Logger::INFO or
30
29
  # greater.
31
30
  def info
32
31
  logger.add(Logger::INFO, nil, facility) { yield } if logger && logger.info?
33
32
  end
34
-
33
+
35
34
  # Displays the result of yielding if the log level is Logger::WARN or
36
35
  # greater. (Called lwarn to avoid shadowing with Kernel#warn.)
37
36
  def lwarn
38
37
  logger.add(Logger::WARN, nil, facility) { yield } if logger && logger.warn?
39
38
  end
40
-
39
+
41
40
  # Displays the result of yielding if the log level is Logger:ERROR or
42
41
  # greater.
43
42
  def error
44
43
  logger.add(Logger::ERROR, nil, facility) { yield } if logger && logger.error?
45
44
  end
46
-
45
+
47
46
  # Displays the result of yielding if the log level is Logger::FATAL or
48
47
  # greater.
49
48
  def fatal
50
49
  logger.add(Logger::FATAL, nil, facility) { yield } if logger && logger.fatal?
51
50
  end
52
-
51
+
53
52
  private
54
-
53
+
55
54
  # Sets the "facility" value, used for reporting where a log message
56
55
  # originates. It defaults to the name of class with the object_id
57
56
  # appended.
58
57
  def facility
59
- @facility ||= self.class.name.gsub(/::/, ".").gsub(/([a-z])([A-Z])/, "\\1_\\2").downcase + "[%x]" % object_id
58
+ @facility ||= self.class.to_s.gsub(/::/, ".").gsub(/([a-z])([A-Z])/, "\\1_\\2").downcase + "[%x]" % object_id
60
59
  end
61
60
  end
62
61
  end
63
- end
62
+ end
@@ -5,7 +5,6 @@ require 'net/ssh/connection/constants'
5
5
 
6
6
  module Net
7
7
  module SSH
8
-
9
8
  # A specialization of Buffer that knows the format of certain common
10
9
  # packet types. It auto-parses those packet types, and allows them to
11
10
  # be accessed via the #[] accessor.
@@ -85,6 +84,7 @@ module Net
85
84
  def [](name)
86
85
  name = name.to_sym
87
86
  raise ArgumentError, "no such element #{name}" unless @named_elements.key?(name)
87
+
88
88
  @named_elements[name]
89
89
  end
90
90
 
@@ -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: ", {}, true)
17
- # password = prompter.ask("password: ", {}, false)
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
@@ -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
@@ -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
@@ -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) #:nodoc:
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
@@ -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
@@ -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