net-ssh 4.1.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +5 -0
  5. data/.rubocop.yml +8 -2
  6. data/.rubocop_todo.yml +405 -552
  7. data/.travis.yml +23 -22
  8. data/CHANGES.txt +112 -1
  9. data/Gemfile +1 -7
  10. data/{Gemfile.norbnacl → Gemfile.noed25519} +1 -1
  11. data/Manifest +4 -5
  12. data/README.md +287 -0
  13. data/Rakefile +40 -29
  14. data/appveyor.yml +12 -6
  15. data/lib/net/ssh.rb +68 -32
  16. data/lib/net/ssh/authentication/agent.rb +234 -222
  17. data/lib/net/ssh/authentication/certificate.rb +175 -164
  18. data/lib/net/ssh/authentication/constants.rb +17 -14
  19. data/lib/net/ssh/authentication/ed25519.rb +162 -141
  20. data/lib/net/ssh/authentication/ed25519_loader.rb +32 -29
  21. data/lib/net/ssh/authentication/key_manager.rb +40 -9
  22. data/lib/net/ssh/authentication/methods/abstract.rb +53 -47
  23. data/lib/net/ssh/authentication/methods/hostbased.rb +32 -33
  24. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +1 -1
  25. data/lib/net/ssh/authentication/methods/none.rb +10 -10
  26. data/lib/net/ssh/authentication/methods/password.rb +13 -13
  27. data/lib/net/ssh/authentication/methods/publickey.rb +56 -55
  28. data/lib/net/ssh/authentication/pageant.rb +468 -465
  29. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  30. data/lib/net/ssh/authentication/session.rb +130 -122
  31. data/lib/net/ssh/buffer.rb +345 -312
  32. data/lib/net/ssh/buffered_io.rb +163 -163
  33. data/lib/net/ssh/config.rb +316 -238
  34. data/lib/net/ssh/connection/channel.rb +670 -650
  35. data/lib/net/ssh/connection/constants.rb +30 -26
  36. data/lib/net/ssh/connection/event_loop.rb +108 -105
  37. data/lib/net/ssh/connection/keepalive.rb +54 -50
  38. data/lib/net/ssh/connection/session.rb +682 -671
  39. data/lib/net/ssh/connection/term.rb +180 -176
  40. data/lib/net/ssh/errors.rb +101 -99
  41. data/lib/net/ssh/key_factory.rb +195 -108
  42. data/lib/net/ssh/known_hosts.rb +161 -152
  43. data/lib/net/ssh/loggable.rb +57 -55
  44. data/lib/net/ssh/packet.rb +82 -78
  45. data/lib/net/ssh/prompt.rb +55 -53
  46. data/lib/net/ssh/proxy/command.rb +104 -89
  47. data/lib/net/ssh/proxy/errors.rb +12 -8
  48. data/lib/net/ssh/proxy/http.rb +93 -91
  49. data/lib/net/ssh/proxy/https.rb +42 -39
  50. data/lib/net/ssh/proxy/jump.rb +50 -47
  51. data/lib/net/ssh/proxy/socks4.rb +0 -2
  52. data/lib/net/ssh/proxy/socks5.rb +11 -12
  53. data/lib/net/ssh/service/forward.rb +370 -317
  54. data/lib/net/ssh/test.rb +83 -77
  55. data/lib/net/ssh/test/channel.rb +146 -142
  56. data/lib/net/ssh/test/extensions.rb +150 -146
  57. data/lib/net/ssh/test/kex.rb +35 -31
  58. data/lib/net/ssh/test/local_packet.rb +48 -44
  59. data/lib/net/ssh/test/packet.rb +87 -84
  60. data/lib/net/ssh/test/remote_packet.rb +35 -31
  61. data/lib/net/ssh/test/script.rb +173 -171
  62. data/lib/net/ssh/test/socket.rb +59 -55
  63. data/lib/net/ssh/transport/algorithms.rb +430 -364
  64. data/lib/net/ssh/transport/cipher_factory.rb +95 -91
  65. data/lib/net/ssh/transport/constants.rb +33 -25
  66. data/lib/net/ssh/transport/ctr.rb +33 -11
  67. data/lib/net/ssh/transport/hmac.rb +15 -13
  68. data/lib/net/ssh/transport/hmac/abstract.rb +82 -63
  69. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  70. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  71. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  72. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  73. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  74. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  75. data/lib/net/ssh/transport/identity_cipher.rb +55 -51
  76. data/lib/net/ssh/transport/kex.rb +14 -13
  77. data/lib/net/ssh/transport/kex/abstract.rb +123 -0
  78. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  79. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +38 -0
  80. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  81. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  82. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +112 -217
  83. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -62
  84. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  85. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  86. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  87. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  88. data/lib/net/ssh/transport/key_expander.rb +29 -25
  89. data/lib/net/ssh/transport/openssl.rb +116 -116
  90. data/lib/net/ssh/transport/packet_stream.rb +223 -190
  91. data/lib/net/ssh/transport/server_version.rb +64 -66
  92. data/lib/net/ssh/transport/session.rb +306 -257
  93. data/lib/net/ssh/transport/state.rb +198 -196
  94. data/lib/net/ssh/verifiers/accept_new.rb +35 -0
  95. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +34 -0
  96. data/lib/net/ssh/verifiers/always.rb +56 -0
  97. data/lib/net/ssh/verifiers/never.rb +21 -0
  98. data/lib/net/ssh/version.rb +55 -53
  99. data/net-ssh-public_cert.pem +18 -19
  100. data/net-ssh.gemspec +12 -11
  101. data/support/ssh_tunnel_bug.rb +2 -2
  102. metadata +86 -75
  103. metadata.gz.sig +0 -0
  104. data/Gemfile.norbnacl.lock +0 -41
  105. data/README.rdoc +0 -169
  106. data/lib/net/ssh/ruby_compat.rb +0 -24
  107. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  108. data/lib/net/ssh/verifiers/null.rb +0 -12
  109. data/lib/net/ssh/verifiers/secure.rb +0 -52
  110. data/lib/net/ssh/verifiers/strict.rb +0 -24
  111. data/support/arcfour_check.rb +0 -20
@@ -1,373 +1,426 @@
1
- # -*- coding: utf-8 -*-
2
1
  require 'net/ssh/loggable'
3
2
 
4
- module Net; module SSH; module Service
5
-
6
- # This class implements various port forwarding services for use by
7
- # Net::SSH clients. The Forward class should never need to be instantiated
8
- # directly; instead, it should be accessed via the singleton instance
9
- # returned by Connection::Session#forward:
10
- #
11
- # ssh.forward.local(1234, "www.capify.org", 80)
12
- class Forward
13
- include Loggable
14
-
15
- # The underlying connection service instance that the port-forwarding
16
- # services employ.
17
- attr_reader :session
18
-
19
- # A simple class for representing a requested remote forwarded port.
20
- Remote = Struct.new(:host, :port) #:nodoc:
21
-
22
- # Instantiates a new Forward service instance atop the given connection
23
- # service session. This will register new channel open handlers to handle
24
- # the specialized channels that the SSH port forwarding protocols employ.
25
- def initialize(session)
26
- @session = session
27
- self.logger = session.logger
28
- @remote_forwarded_ports = {}
29
- @local_forwarded_ports = {}
30
- @agent_forwarded = false
31
-
32
- session.on_open_channel('forwarded-tcpip', &method(:forwarded_tcpip))
33
- session.on_open_channel('auth-agent', &method(:auth_agent_channel))
34
- session.on_open_channel('auth-agent@openssh.com', &method(:auth_agent_channel))
35
- end
36
-
37
- # Starts listening for connections on the local host, and forwards them
38
- # to the specified remote host/port via the SSH connection. This method
39
- # accepts either three or four arguments. When four arguments are given,
40
- # they are:
41
- #
42
- # * the local address to bind to
43
- # * the local port to listen on
44
- # * the remote host to forward connections to
45
- # * the port on the remote host to connect to
46
- #
47
- # If three arguments are given, it is as if the local bind address is
48
- # "127.0.0.1", and the rest are applied as above.
49
- #
50
- # To request an ephemeral port on the remote server, provide 0 (zero) for
51
- # the port number. In all cases, this method will return the port that
52
- # has been assigned.
53
- #
54
- # ssh.forward.local(1234, "www.capify.org", 80)
55
- # assigned_port = ssh.forward.local("0.0.0.0", 0, "www.capify.org", 80)
56
- def local(*args)
57
- if args.length < 3 || args.length > 4
58
- raise ArgumentError, "expected 3 or 4 parameters, got #{args.length}"
59
- end
3
+ module Net
4
+ module SSH
5
+ module Service
6
+
7
+ # This class implements various port forwarding services for use by
8
+ # Net::SSH clients. The Forward class should never need to be instantiated
9
+ # directly; instead, it should be accessed via the singleton instance
10
+ # returned by Connection::Session#forward:
11
+ #
12
+ # ssh.forward.local(1234, "www.capify.org", 80)
13
+ class Forward
14
+ include Loggable
15
+
16
+ # The underlying connection service instance that the port-forwarding
17
+ # services employ.
18
+ attr_reader :session
19
+
20
+ # A simple class for representing a requested remote forwarded port.
21
+ Remote = Struct.new(:host, :port) #:nodoc:
22
+
23
+ # Instantiates a new Forward service instance atop the given connection
24
+ # service session. This will register new channel open handlers to handle
25
+ # the specialized channels that the SSH port forwarding protocols employ.
26
+ def initialize(session)
27
+ @session = session
28
+ self.logger = session.logger
29
+ @remote_forwarded_ports = {}
30
+ @local_forwarded_ports = {}
31
+ @agent_forwarded = false
32
+ @local_forwarded_sockets = {}
33
+
34
+ session.on_open_channel('forwarded-tcpip', &method(:forwarded_tcpip))
35
+ session.on_open_channel('auth-agent', &method(:auth_agent_channel))
36
+ session.on_open_channel('auth-agent@openssh.com', &method(:auth_agent_channel))
37
+ end
60
38
 
61
- local_port_type = :long
39
+ # Starts listening for connections on the local host, and forwards them
40
+ # to the specified remote host/port via the SSH connection. This method
41
+ # accepts either three or four arguments. When four arguments are given,
42
+ # they are:
43
+ #
44
+ # * the local address to bind to
45
+ # * the local port to listen on
46
+ # * the remote host to forward connections to
47
+ # * the port on the remote host to connect to
48
+ #
49
+ # If three arguments are given, it is as if the local bind address is
50
+ # "127.0.0.1", and the rest are applied as above.
51
+ #
52
+ # To request an ephemeral port on the remote server, provide 0 (zero) for
53
+ # the port number. In all cases, this method will return the port that
54
+ # has been assigned.
55
+ #
56
+ # ssh.forward.local(1234, "www.capify.org", 80)
57
+ # assigned_port = ssh.forward.local("0.0.0.0", 0, "www.capify.org", 80)
58
+ def local(*args)
59
+ if args.length < 3 || args.length > 4
60
+ raise ArgumentError, "expected 3 or 4 parameters, got #{args.length}"
61
+ end
62
62
 
63
- socket = begin
64
- if defined?(UNIXServer) and args.first.class == UNIXServer
65
- local_port_type = :string
66
- args.shift
67
- else
68
- bind_address = "127.0.0.1"
69
- bind_address = args.shift if args.first.is_a?(String) && args.first =~ /\D/
70
- local_port = args.shift.to_i
71
63
  local_port_type = :long
72
- TCPServer.new(bind_address, local_port)
73
- end
74
- end
75
64
 
76
- local_port = socket.addr[1] if local_port == 0 # ephemeral port was requested
77
- remote_host = args.shift
78
- remote_port = args.shift.to_i
65
+ socket = begin
66
+ if defined?(UNIXServer) and args.first.class == UNIXServer
67
+ local_port_type = :string
68
+ args.shift
69
+ else
70
+ bind_address = "127.0.0.1"
71
+ bind_address = args.shift if args.first.is_a?(String) && args.first =~ /\D/
72
+ local_port = args.shift.to_i
73
+ local_port_type = :long
74
+ TCPServer.new(bind_address, local_port)
75
+ end
76
+ end
79
77
 
80
- @local_forwarded_ports[[local_port, bind_address]] = socket
78
+ local_port = socket.addr[1] if local_port == 0 # ephemeral port was requested
79
+ remote_host = args.shift
80
+ remote_port = args.shift.to_i
81
81
 
82
- session.listen_to(socket) do |server|
83
- client = server.accept
84
- debug { "received connection on #{socket}" }
82
+ @local_forwarded_ports[[local_port, bind_address]] = socket
85
83
 
86
- channel = session.open_channel("direct-tcpip", :string, remote_host, :long, remote_port, :string, bind_address, local_port_type, local_port) do |achannel|
87
- achannel.info { "direct channel established" }
88
- end
84
+ session.listen_to(socket) do |server|
85
+ client = server.accept
86
+ debug { "received connection on #{socket}" }
87
+
88
+ channel = session.open_channel("direct-tcpip", :string, remote_host, :long,
89
+ remote_port, :string, bind_address, local_port_type, local_port) do |achannel|
90
+ achannel.info { "direct channel established" }
91
+ end
89
92
 
90
- prepare_client(client, channel, :local)
93
+ prepare_client(client, channel, :local)
91
94
 
92
- channel.on_open_failed do |ch, code, description|
93
- channel.error { "could not establish direct channel: #{description} (#{code})" }
94
- session.stop_listening_to(channel[:socket])
95
- channel[:socket].close
95
+ channel.on_open_failed do |ch, code, description|
96
+ channel.error { "could not establish direct channel: #{description} (#{code})" }
97
+ session.stop_listening_to(channel[:socket])
98
+ channel[:socket].close
99
+ end
100
+ end
101
+
102
+ local_port
96
103
  end
97
- end
98
104
 
99
- local_port
100
- end
105
+ # Terminates an active local forwarded port.
106
+ #
107
+ # ssh.forward.cancel_local(1234)
108
+ # ssh.forward.cancel_local(1234, "0.0.0.0")
109
+ def cancel_local(port, bind_address="127.0.0.1")
110
+ socket = @local_forwarded_ports.delete([port, bind_address])
111
+ socket.shutdown rescue nil
112
+ socket.close rescue nil
113
+ session.stop_listening_to(socket)
114
+ end
101
115
 
102
- # Terminates an active local forwarded port. If no such forwarded port
103
- # exists, this will raise an exception. Otherwise, the forwarded connection
104
- # is terminated.
105
- #
106
- # ssh.forward.cancel_local(1234)
107
- # ssh.forward.cancel_local(1234, "0.0.0.0")
108
- def cancel_local(port, bind_address="127.0.0.1")
109
- socket = @local_forwarded_ports.delete([port, bind_address])
110
- socket.shutdown rescue nil
111
- socket.close rescue nil
112
- session.stop_listening_to(socket)
113
- end
116
+ # Returns a list of all active locally forwarded ports. The returned value
117
+ # is an array of arrays, where each element is a two-element tuple
118
+ # consisting of the local port and bind address corresponding to the
119
+ # forwarding port.
120
+ def active_locals
121
+ @local_forwarded_ports.keys
122
+ end
114
123
 
115
- # Returns a list of all active locally forwarded ports. The returned value
116
- # is an array of arrays, where each element is a two-element tuple
117
- # consisting of the local port and bind address corresponding to the
118
- # forwarding port.
119
- def active_locals
120
- @local_forwarded_ports.keys
121
- end
124
+ # Starts listening for connections on the local host, and forwards them
125
+ # to the specified remote socket via the SSH connection. This will
126
+ # (re)create the local socket file. The remote server needs to have the
127
+ # socket file already available.
128
+ #
129
+ # ssh.forward.local_socket('/tmp/local.sock', '/tmp/remote.sock')
130
+ def local_socket(local_socket_path, remote_socket_path)
131
+ File.delete(local_socket_path) if File.exist?(local_socket_path)
132
+ socket = Socket.unix_server_socket(local_socket_path)
133
+
134
+ @local_forwarded_sockets[local_socket_path] = socket
135
+
136
+ session.listen_to(socket) do |server|
137
+ client = server.accept[0]
138
+ debug { "received connection on #{socket}" }
139
+
140
+ channel = session.open_channel("direct-streamlocal@openssh.com",
141
+ :string, remote_socket_path,
142
+ :string, nil,
143
+ :long, 0) do |achannel|
144
+ achannel.info { "direct channel established" }
145
+ end
146
+
147
+ prepare_client(client, channel, :local)
122
148
 
123
- # Requests that all connections on the given remote-port be forwarded via
124
- # the local host to the given port/host. The last argument describes the
125
- # bind address on the remote host, and defaults to 127.0.0.1.
126
- #
127
- # This method will return immediately, but the port will not actually be
128
- # forwarded immediately. If the remote server is not able to begin the
129
- # listener for this request, an exception will be raised asynchronously.
130
- #
131
- # To request an ephemeral port on the remote server, provide 0 (zero) for
132
- # the port number. The assigned port will show up in the # #active_remotes
133
- # list.
134
- #
135
- # remote_host is interpreted by the server per RFC 4254, which has these
136
- # special values:
137
- #
138
- # - "" means that connections are to be accepted on all protocol
139
- # families supported by the SSH implementation.
140
- # - "0.0.0.0" means to listen on all IPv4 addresses.
141
- # - "::" means to listen on all IPv6 addresses.
142
- # - "localhost" means to listen on all protocol families supported by
143
- # the SSH implementation on loopback addresses only ([RFC3330] and
144
- # [RFC3513]).
145
- # - "127.0.0.1" and "::1" indicate listening on the loopback
146
- # interfaces for IPv4 and IPv6, respectively.
147
- #
148
- # You may pass a block that will be called when the the port forward
149
- # request receives a response. This block will be passed the remote_port
150
- # that was actually bound to, or nil if the binding failed. If the block
151
- # returns :no_exception, the "failed binding" exception will not be thrown.
152
- #
153
- # If you want to block until the port is active, you could do something
154
- # like this:
155
- #
156
- # got_remote_port = nil
157
- # remote(port, host, remote_port, remote_host) do |actual_remote_port|
158
- # got_remote_port = actual_remote_port || :error
159
- # :no_exception # will yield the exception on my own thread
160
- # end
161
- # session.loop { !got_remote_port }
162
- # if got_remote_port == :error
163
- # raise Net::SSH::Exception, "remote forwarding request failed"
164
- # end
165
- #
166
- def remote(port, host, remote_port, remote_host="127.0.0.1")
167
- session.send_global_request("tcpip-forward", :string, remote_host, :long, remote_port) do |success, response|
168
- if success
169
- remote_port = response.read_long if remote_port == 0
170
- debug { "remote forward from remote #{remote_host}:#{remote_port} to #{host}:#{port} established" }
171
- @remote_forwarded_ports[[remote_port, remote_host]] = Remote.new(host, port)
172
- yield remote_port, remote_host if block_given?
173
- else
174
- instruction = if block_given?
175
- yield :error
149
+ channel.on_open_failed do |ch, code, description|
150
+ channel.error { "could not establish direct channel: #{description} (#{code})" }
151
+ session.stop_listening_to(channel[:socket])
152
+ channel[:socket].close
153
+ end
176
154
  end
177
- unless instruction == :no_exception
178
- error { "remote forwarding request failed" }
179
- raise Net::SSH::Exception, "remote forwarding request failed"
155
+
156
+ local_socket_path
157
+ end
158
+
159
+ # Terminates an active local forwarded socket.
160
+ #
161
+ # ssh.forward.cancel_local_socket('/tmp/foo.sock')
162
+ def cancel_local_socket(local_socket_path)
163
+ socket = @local_forwarded_sockets.delete(local_socket_path)
164
+ socket.shutdown rescue nil
165
+ socket.close rescue nil
166
+ session.stop_listening_to(socket)
167
+ end
168
+
169
+ # Returns a list of all active locally forwarded sockets. The returned value
170
+ # is an array of Unix domain socket file paths.
171
+ def active_local_sockets
172
+ @local_forwarded_sockets.keys
173
+ end
174
+
175
+ # Requests that all connections on the given remote-port be forwarded via
176
+ # the local host to the given port/host. The last argument describes the
177
+ # bind address on the remote host, and defaults to 127.0.0.1.
178
+ #
179
+ # This method will return immediately, but the port will not actually be
180
+ # forwarded immediately. If the remote server is not able to begin the
181
+ # listener for this request, an exception will be raised asynchronously.
182
+ #
183
+ # To request an ephemeral port on the remote server, provide 0 (zero) for
184
+ # the port number. The assigned port will show up in the # #active_remotes
185
+ # list.
186
+ #
187
+ # remote_host is interpreted by the server per RFC 4254, which has these
188
+ # special values:
189
+ #
190
+ # - "" means that connections are to be accepted on all protocol
191
+ # families supported by the SSH implementation.
192
+ # - "0.0.0.0" means to listen on all IPv4 addresses.
193
+ # - "::" means to listen on all IPv6 addresses.
194
+ # - "localhost" means to listen on all protocol families supported by
195
+ # the SSH implementation on loopback addresses only ([RFC3330] and
196
+ # [RFC3513]).
197
+ # - "127.0.0.1" and "::1" indicate listening on the loopback
198
+ # interfaces for IPv4 and IPv6, respectively.
199
+ #
200
+ # You may pass a block that will be called when the the port forward
201
+ # request receives a response. This block will be passed the remote_port
202
+ # that was actually bound to, or nil if the binding failed. If the block
203
+ # returns :no_exception, the "failed binding" exception will not be thrown.
204
+ #
205
+ # If you want to block until the port is active, you could do something
206
+ # like this:
207
+ #
208
+ # got_remote_port = nil
209
+ # remote(port, host, remote_port, remote_host) do |actual_remote_port|
210
+ # got_remote_port = actual_remote_port || :error
211
+ # :no_exception # will yield the exception on my own thread
212
+ # end
213
+ # session.loop { !got_remote_port }
214
+ # if got_remote_port == :error
215
+ # raise Net::SSH::Exception, "remote forwarding request failed"
216
+ # end
217
+ #
218
+ def remote(port, host, remote_port, remote_host="127.0.0.1")
219
+ session.send_global_request("tcpip-forward", :string, remote_host, :long, remote_port) do |success, response|
220
+ if success
221
+ remote_port = response.read_long if remote_port == 0
222
+ debug { "remote forward from remote #{remote_host}:#{remote_port} to #{host}:#{port} established" }
223
+ @remote_forwarded_ports[[remote_port, remote_host]] = Remote.new(host, port)
224
+ yield remote_port, remote_host if block_given?
225
+ else
226
+ instruction = if block_given?
227
+ yield :error
228
+ end
229
+ unless instruction == :no_exception
230
+ error { "remote forwarding request failed" }
231
+ raise Net::SSH::Exception, "remote forwarding request failed"
232
+ end
233
+ end
180
234
  end
181
235
  end
182
- end
183
- end
184
236
 
185
- # an alias, for token backwards compatibility with the 1.x API
186
- alias :remote_to :remote
187
-
188
- # Requests that a remote forwarded port be cancelled. The remote forwarded
189
- # port on the remote host, bound to the given address on the remote host,
190
- # will be terminated, but not immediately. This method returns immediately
191
- # after queueing the request to be sent to the server. If for some reason
192
- # the port cannot be cancelled, an exception will be raised (asynchronously).
193
- #
194
- # If you want to know when the connection has been cancelled, it will no
195
- # longer be present in the #active_remotes list. If you want to block until
196
- # the port is no longer active, you could do something like this:
197
- #
198
- # ssh.forward.cancel_remote(1234, "0.0.0.0")
199
- # ssh.loop { ssh.forward.active_remotes.include?([1234, "0.0.0.0"]) }
200
- def cancel_remote(port, host="127.0.0.1")
201
- session.send_global_request("cancel-tcpip-forward", :string, host, :long, port) do |success, response|
202
- if success
203
- @remote_forwarded_ports.delete([port, host])
204
- else
205
- raise Net::SSH::Exception, "could not cancel remote forward request on #{host}:#{port}"
237
+ # an alias, for token backwards compatibility with the 1.x API
238
+ alias :remote_to :remote
239
+
240
+ # Requests that a remote forwarded port be cancelled. The remote forwarded
241
+ # port on the remote host, bound to the given address on the remote host,
242
+ # will be terminated, but not immediately. This method returns immediately
243
+ # after queueing the request to be sent to the server. If for some reason
244
+ # the port cannot be cancelled, an exception will be raised (asynchronously).
245
+ #
246
+ # If you want to know when the connection has been cancelled, it will no
247
+ # longer be present in the #active_remotes list. If you want to block until
248
+ # the port is no longer active, you could do something like this:
249
+ #
250
+ # ssh.forward.cancel_remote(1234, "0.0.0.0")
251
+ # ssh.loop { ssh.forward.active_remotes.include?([1234, "0.0.0.0"]) }
252
+ def cancel_remote(port, host="127.0.0.1")
253
+ session.send_global_request("cancel-tcpip-forward", :string, host, :long, port) do |success, response|
254
+ if success
255
+ @remote_forwarded_ports.delete([port, host])
256
+ else
257
+ raise Net::SSH::Exception, "could not cancel remote forward request on #{host}:#{port}"
258
+ end
259
+ end
206
260
  end
207
- end
208
- end
209
261
 
210
- # Returns all active forwarded remote ports. The returned value is an
211
- # array of two-element tuples, where the first element is the port on the
212
- # remote host and the second is the bind address.
213
- def active_remotes
214
- @remote_forwarded_ports.keys
215
- end
262
+ # Returns all active forwarded remote ports. The returned value is an
263
+ # array of two-element tuples, where the first element is the port on the
264
+ # remote host and the second is the bind address.
265
+ def active_remotes
266
+ @remote_forwarded_ports.keys
267
+ end
216
268
 
217
- # Returns all active remote forwarded ports and where they forward to. The
218
- # returned value is a hash from [<forwarding port on the local host>, <local forwarding address>]
219
- # to [<port on the remote host>, <remote bind address>].
220
- def active_remote_destinations
221
- @remote_forwarded_ports.inject({}) do |result, (remote, local)|
222
- result[[local.port, local.host]] = remote
223
- result
224
- end
225
- end
269
+ # Returns all active remote forwarded ports and where they forward to. The
270
+ # returned value is a hash from [<forwarding port on the local host>, <local forwarding address>]
271
+ # to [<port on the remote host>, <remote bind address>].
272
+ def active_remote_destinations
273
+ @remote_forwarded_ports.each_with_object({}) do |(remote, local), result|
274
+ result[[local.port, local.host]] = remote
275
+ end
276
+ end
226
277
 
227
- # Enables SSH agent forwarding on the given channel. The forwarded agent
228
- # will remain active even after the channel closes--the channel is only
229
- # used as the transport for enabling the forwarded connection. You should
230
- # never need to call this directly--it is called automatically the first
231
- # time a session channel is opened, when the connection was created with
232
- # :forward_agent set to true:
233
- #
234
- # Net::SSH.start("remote.host", "me", :forward_agent => true) do |ssh|
235
- # ssh.open_channel do |ch|
236
- # # agent will be automatically forwarded by this point
237
- # end
238
- # ssh.loop
239
- # end
240
- def agent(channel)
241
- return if @agent_forwarded
242
- @agent_forwarded = true
243
-
244
- channel.send_channel_request("auth-agent-req@openssh.com") do |achannel, success|
245
- if success
246
- debug { "authentication agent forwarding is active" }
247
- else
248
- achannel.send_channel_request("auth-agent-req") do |a2channel, success2|
249
- if success2
278
+ # Enables SSH agent forwarding on the given channel. The forwarded agent
279
+ # will remain active even after the channel closes--the channel is only
280
+ # used as the transport for enabling the forwarded connection. You should
281
+ # never need to call this directly--it is called automatically the first
282
+ # time a session channel is opened, when the connection was created with
283
+ # :forward_agent set to true:
284
+ #
285
+ # Net::SSH.start("remote.host", "me", :forward_agent => true) do |ssh|
286
+ # ssh.open_channel do |ch|
287
+ # # agent will be automatically forwarded by this point
288
+ # end
289
+ # ssh.loop
290
+ # end
291
+ def agent(channel)
292
+ return if @agent_forwarded
293
+ @agent_forwarded = true
294
+
295
+ channel.send_channel_request("auth-agent-req@openssh.com") do |achannel, success|
296
+ if success
250
297
  debug { "authentication agent forwarding is active" }
251
298
  else
252
- error { "could not establish forwarding of authentication agent" }
299
+ achannel.send_channel_request("auth-agent-req") do |a2channel, success2|
300
+ if success2
301
+ debug { "authentication agent forwarding is active" }
302
+ else
303
+ error { "could not establish forwarding of authentication agent" }
304
+ end
305
+ end
253
306
  end
254
307
  end
255
308
  end
256
- end
257
- end
258
309
 
259
- private
310
+ private
260
311
 
261
- # Perform setup operations that are common to all forwarded channels.
262
- # +client+ is a socket, +channel+ is the channel that was just created,
263
- # and +type+ is an arbitrary string describing the type of the channel.
264
- def prepare_client(client, channel, type)
265
- client.extend(Net::SSH::BufferedIo)
266
- client.extend(Net::SSH::ForwardedBufferedIo)
267
- client.logger = logger
312
+ # Perform setup operations that are common to all forwarded channels.
313
+ # +client+ is a socket, +channel+ is the channel that was just created,
314
+ # and +type+ is an arbitrary string describing the type of the channel.
315
+ def prepare_client(client, channel, type)
316
+ client.extend(Net::SSH::BufferedIo)
317
+ client.extend(Net::SSH::ForwardedBufferedIo)
318
+ client.logger = logger
268
319
 
269
- session.listen_to(client)
270
- channel[:socket] = client
320
+ session.listen_to(client)
321
+ channel[:socket] = client
271
322
 
272
- channel.on_data do |ch, data|
273
- debug { "data:#{data.length} on #{type} forwarded channel" }
274
- ch[:socket].enqueue(data)
275
- end
323
+ channel.on_data do |ch, data|
324
+ debug { "data:#{data.length} on #{type} forwarded channel" }
325
+ ch[:socket].enqueue(data)
326
+ end
276
327
 
277
- channel.on_eof do |ch|
278
- debug { "eof #{type} on #{type} forwarded channel" }
279
- begin
280
- ch[:socket].send_pending
281
- ch[:socket].shutdown Socket::SHUT_WR
282
- rescue IOError => e
283
- if e.message =~ /closed/ then
328
+ channel.on_eof do |ch|
329
+ debug { "eof #{type} on #{type} forwarded channel" }
330
+ begin
331
+ ch[:socket].send_pending
332
+ ch[:socket].shutdown Socket::SHUT_WR
333
+ rescue IOError => e
334
+ if e.message =~ /closed/ then
335
+ debug { "epipe in on_eof => shallowing exception:#{e}" }
336
+ else
337
+ raise
338
+ end
339
+ rescue Errno::EPIPE => e
284
340
  debug { "epipe in on_eof => shallowing exception:#{e}" }
285
- else
286
- raise
341
+ rescue Errno::ENOTCONN => e
342
+ debug { "enotconn in on_eof => shallowing exception:#{e}" }
287
343
  end
288
- rescue Errno::EPIPE => e
289
- debug { "epipe in on_eof => shallowing exception:#{e}" }
290
- rescue Errno::ENOTCONN => e
291
- debug { "enotconn in on_eof => shallowing exception:#{e}" }
292
344
  end
293
- end
294
345
 
295
- channel.on_close do |ch|
296
- debug { "closing #{type} forwarded channel" }
297
- ch[:socket].close if !client.closed?
298
- session.stop_listening_to(ch[:socket])
299
- end
346
+ channel.on_close do |ch|
347
+ debug { "closing #{type} forwarded channel" }
348
+ ch[:socket].close if !client.closed?
349
+ session.stop_listening_to(ch[:socket])
350
+ end
300
351
 
301
- channel.on_process do |ch|
302
- if ch[:socket].closed?
303
- ch.info { "#{type} forwarded connection closed" }
304
- ch.close
305
- elsif ch[:socket].available > 0
306
- data = ch[:socket].read_available(8192)
307
- ch.debug { "read #{data.length} bytes from client, sending over #{type} forwarded connection" }
308
- ch.send_data(data)
352
+ channel.on_process do |ch|
353
+ if ch[:socket].closed?
354
+ ch.info { "#{type} forwarded connection closed" }
355
+ ch.close
356
+ elsif ch[:socket].available > 0
357
+ data = ch[:socket].read_available(8192)
358
+ ch.debug { "read #{data.length} bytes from client, sending over #{type} forwarded connection" }
359
+ ch.send_data(data)
360
+ end
309
361
  end
310
362
  end
311
- end
312
363
 
313
- # not a real socket, so use a simpler behaviour
314
- def prepare_simple_client(client, channel, type)
315
- channel[:socket] = client
364
+ # not a real socket, so use a simpler behaviour
365
+ def prepare_simple_client(client, channel, type)
366
+ channel[:socket] = client
316
367
 
317
- channel.on_data do |ch, data|
318
- ch.debug { "data:#{data.length} on #{type} forwarded channel" }
319
- ch[:socket].send(data)
320
- end
368
+ channel.on_data do |ch, data|
369
+ ch.debug { "data:#{data.length} on #{type} forwarded channel" }
370
+ ch[:socket].send(data)
371
+ end
321
372
 
322
- channel.on_process do |ch|
323
- data = ch[:socket].read(8192)
324
- if data
325
- ch.debug { "read #{data.length} bytes from client, sending over #{type} forwarded connection" }
326
- ch.send_data(data)
373
+ channel.on_process do |ch|
374
+ data = ch[:socket].read(8192)
375
+ if data
376
+ ch.debug { "read #{data.length} bytes from client, sending over #{type} forwarded connection" }
377
+ ch.send_data(data)
378
+ end
327
379
  end
328
380
  end
329
- end
330
381
 
331
- # The callback used when a new "forwarded-tcpip" channel is requested
332
- # by the server. This will open a new socket to the host/port specified
333
- # when the forwarded connection was first requested.
334
- def forwarded_tcpip(session, channel, packet)
335
- connected_address = packet.read_string
336
- connected_port = packet.read_long
337
- originator_address = packet.read_string
338
- originator_port = packet.read_long
382
+ # The callback used when a new "forwarded-tcpip" channel is requested
383
+ # by the server. This will open a new socket to the host/port specified
384
+ # when the forwarded connection was first requested.
385
+ def forwarded_tcpip(session, channel, packet)
386
+ connected_address = packet.read_string
387
+ connected_port = packet.read_long
388
+ originator_address = packet.read_string
389
+ originator_port = packet.read_long
339
390
 
340
- remote = @remote_forwarded_ports[[connected_port, connected_address]]
391
+ remote = @remote_forwarded_ports[[connected_port, connected_address]]
341
392
 
342
- if remote.nil?
343
- raise Net::SSH::ChannelOpenFailed.new(1, "unknown request from remote forwarded connection on #{connected_address}:#{connected_port}")
344
- end
393
+ if remote.nil?
394
+ raise Net::SSH::ChannelOpenFailed.new(1, "unknown request from remote forwarded connection on #{connected_address}:#{connected_port}")
395
+ end
345
396
 
346
- client = TCPSocket.new(remote.host, remote.port)
347
- info { "connected #{connected_address}:#{connected_port} originator #{originator_address}:#{originator_port}" }
397
+ client = TCPSocket.new(remote.host, remote.port)
398
+ info { "connected #{connected_address}:#{connected_port} originator #{originator_address}:#{originator_port}" }
348
399
 
349
- prepare_client(client, channel, :remote)
350
- rescue SocketError => err
351
- raise Net::SSH::ChannelOpenFailed.new(2, "could not connect to remote host (#{remote.host}:#{remote.port}): #{err.message}")
352
- end
400
+ prepare_client(client, channel, :remote)
401
+ rescue SocketError => err
402
+ raise Net::SSH::ChannelOpenFailed.new(2, "could not connect to remote host (#{remote.host}:#{remote.port}): #{err.message}")
403
+ end
404
+
405
+ # The callback used when an auth-agent channel is requested by the server.
406
+ def auth_agent_channel(session, channel, packet)
407
+ info { "opening auth-agent channel" }
408
+ channel[:invisible] = true
353
409
 
354
- # The callback used when an auth-agent channel is requested by the server.
355
- def auth_agent_channel(session, channel, packet)
356
- info { "opening auth-agent channel" }
357
- channel[:invisible] = true
358
-
359
- begin
360
- agent = Authentication::Agent.connect(logger, session.options[:agent_socket_factory])
361
- if (agent.socket.is_a? ::IO)
362
- prepare_client(agent.socket, channel, :agent)
363
- else
364
- prepare_simple_client(agent.socket, channel, :agent)
410
+ begin
411
+ agent = Authentication::Agent.connect(logger, session.options[:agent_socket_factory])
412
+ if (agent.socket.is_a? ::IO)
413
+ prepare_client(agent.socket, channel, :agent)
414
+ else
415
+ prepare_simple_client(agent.socket, channel, :agent)
416
+ end
417
+ rescue Exception => e
418
+ error { "attempted to connect to agent but failed: #{e.class.name} (#{e.message})" }
419
+ raise Net::SSH::ChannelOpenFailed.new(2, "could not connect to authentication agent")
365
420
  end
366
- rescue Exception => e
367
- error { "attempted to connect to agent but failed: #{e.class.name} (#{e.message})" }
368
- raise Net::SSH::ChannelOpenFailed.new(2, "could not connect to authentication agent")
369
421
  end
370
422
  end
371
- end
372
423
 
373
- end; end; end
424
+ end
425
+ end
426
+ end