ddollar-net-ssh 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +42 -0
- data/Manifest +101 -0
- data/README.rdoc +110 -0
- data/Rakefile +26 -0
- data/THANKS.rdoc +16 -0
- data/lib/net/ssh.rb +199 -0
- data/lib/net/ssh/authentication/agent.rb +175 -0
- data/lib/net/ssh/authentication/constants.rb +18 -0
- data/lib/net/ssh/authentication/key_manager.rb +169 -0
- data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
- data/lib/net/ssh/authentication/methods/hostbased.rb +71 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +66 -0
- data/lib/net/ssh/authentication/methods/password.rb +39 -0
- data/lib/net/ssh/authentication/methods/publickey.rb +92 -0
- data/lib/net/ssh/authentication/pageant.rb +176 -0
- data/lib/net/ssh/authentication/session.rb +127 -0
- data/lib/net/ssh/buffer.rb +339 -0
- data/lib/net/ssh/buffered_io.rb +149 -0
- data/lib/net/ssh/config.rb +173 -0
- data/lib/net/ssh/connection/channel.rb +625 -0
- data/lib/net/ssh/connection/constants.rb +33 -0
- data/lib/net/ssh/connection/session.rb +569 -0
- data/lib/net/ssh/connection/term.rb +178 -0
- data/lib/net/ssh/errors.rb +85 -0
- data/lib/net/ssh/key_factory.rb +85 -0
- data/lib/net/ssh/known_hosts.rb +129 -0
- data/lib/net/ssh/loggable.rb +61 -0
- data/lib/net/ssh/packet.rb +102 -0
- data/lib/net/ssh/prompt.rb +93 -0
- data/lib/net/ssh/proxy/errors.rb +14 -0
- data/lib/net/ssh/proxy/http.rb +94 -0
- data/lib/net/ssh/proxy/socks4.rb +70 -0
- data/lib/net/ssh/proxy/socks5.rb +128 -0
- data/lib/net/ssh/service/forward.rb +267 -0
- data/lib/net/ssh/test.rb +89 -0
- data/lib/net/ssh/test/channel.rb +129 -0
- data/lib/net/ssh/test/extensions.rb +152 -0
- data/lib/net/ssh/test/kex.rb +44 -0
- data/lib/net/ssh/test/local_packet.rb +51 -0
- data/lib/net/ssh/test/packet.rb +81 -0
- data/lib/net/ssh/test/remote_packet.rb +38 -0
- data/lib/net/ssh/test/script.rb +157 -0
- data/lib/net/ssh/test/socket.rb +59 -0
- data/lib/net/ssh/transport/algorithms.rb +384 -0
- data/lib/net/ssh/transport/cipher_factory.rb +72 -0
- data/lib/net/ssh/transport/constants.rb +30 -0
- data/lib/net/ssh/transport/hmac.rb +31 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +48 -0
- data/lib/net/ssh/transport/hmac/md5.rb +12 -0
- data/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
- data/lib/net/ssh/transport/hmac/none.rb +15 -0
- data/lib/net/ssh/transport/hmac/sha1.rb +13 -0
- data/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
- data/lib/net/ssh/transport/identity_cipher.rb +40 -0
- data/lib/net/ssh/transport/kex.rb +13 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +77 -0
- data/lib/net/ssh/transport/openssl.rb +128 -0
- data/lib/net/ssh/transport/packet_stream.rb +230 -0
- data/lib/net/ssh/transport/server_version.rb +61 -0
- data/lib/net/ssh/transport/session.rb +262 -0
- data/lib/net/ssh/transport/state.rb +170 -0
- data/lib/net/ssh/verifiers/lenient.rb +30 -0
- data/lib/net/ssh/verifiers/null.rb +12 -0
- data/lib/net/ssh/verifiers/strict.rb +53 -0
- data/lib/net/ssh/version.rb +60 -0
- data/net-ssh.gemspec +56 -0
- data/setup.rb +1585 -0
- data/test/authentication/methods/common.rb +28 -0
- data/test/authentication/methods/test_abstract.rb +51 -0
- data/test/authentication/methods/test_hostbased.rb +108 -0
- data/test/authentication/methods/test_keyboard_interactive.rb +98 -0
- data/test/authentication/methods/test_password.rb +50 -0
- data/test/authentication/methods/test_publickey.rb +123 -0
- data/test/authentication/test_agent.rb +205 -0
- data/test/authentication/test_key_manager.rb +100 -0
- data/test/authentication/test_session.rb +93 -0
- data/test/common.rb +106 -0
- data/test/configs/exact_match +8 -0
- data/test/configs/wild_cards +14 -0
- data/test/connection/test_channel.rb +452 -0
- data/test/connection/test_session.rb +483 -0
- data/test/test_all.rb +6 -0
- data/test/test_buffer.rb +336 -0
- data/test/test_buffered_io.rb +63 -0
- data/test/test_config.rb +78 -0
- data/test/test_key_factory.rb +67 -0
- data/test/transport/hmac/test_md5.rb +34 -0
- data/test/transport/hmac/test_md5_96.rb +25 -0
- data/test/transport/hmac/test_none.rb +34 -0
- data/test/transport/hmac/test_sha1.rb +34 -0
- data/test/transport/hmac/test_sha1_96.rb +25 -0
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
- data/test/transport/test_algorithms.rb +302 -0
- data/test/transport/test_cipher_factory.rb +163 -0
- data/test/transport/test_hmac.rb +34 -0
- data/test/transport/test_identity_cipher.rb +40 -0
- data/test/transport/test_packet_stream.rb +433 -0
- data/test/transport/test_server_version.rb +55 -0
- data/test/transport/test_session.rb +312 -0
- data/test/transport/test_state.rb +173 -0
- metadata +222 -0
@@ -0,0 +1,262 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
require 'net/ssh/errors'
|
5
|
+
require 'net/ssh/loggable'
|
6
|
+
require 'net/ssh/version'
|
7
|
+
require 'net/ssh/transport/algorithms'
|
8
|
+
require 'net/ssh/transport/constants'
|
9
|
+
require 'net/ssh/transport/packet_stream'
|
10
|
+
require 'net/ssh/transport/server_version'
|
11
|
+
require 'net/ssh/verifiers/null'
|
12
|
+
require 'net/ssh/verifiers/strict'
|
13
|
+
require 'net/ssh/verifiers/lenient'
|
14
|
+
|
15
|
+
module Net; module SSH; module Transport
|
16
|
+
|
17
|
+
# The transport layer represents the lowest level of the SSH protocol, and
|
18
|
+
# implements basic message exchanging and protocol initialization. It will
|
19
|
+
# never be instantiated directly (unless you really know what you're about),
|
20
|
+
# but will instead be created for you automatically when you create a new
|
21
|
+
# SSH session via Net::SSH.start.
|
22
|
+
class Session
|
23
|
+
include Constants, Loggable
|
24
|
+
|
25
|
+
# The standard port for the SSH protocol.
|
26
|
+
DEFAULT_PORT = 22
|
27
|
+
|
28
|
+
# The host to connect to, as given to the constructor.
|
29
|
+
attr_reader :host
|
30
|
+
|
31
|
+
# The port number to connect to, as given in the options to the constructor.
|
32
|
+
# If no port number was given, this will default to DEFAULT_PORT.
|
33
|
+
attr_reader :port
|
34
|
+
|
35
|
+
# The underlying socket object being used to communicate with the remote
|
36
|
+
# host.
|
37
|
+
attr_reader :socket
|
38
|
+
|
39
|
+
# The ServerVersion instance that encapsulates the negotiated protocol
|
40
|
+
# version.
|
41
|
+
attr_reader :server_version
|
42
|
+
|
43
|
+
# The Algorithms instance used to perform key exchanges.
|
44
|
+
attr_reader :algorithms
|
45
|
+
|
46
|
+
# The host-key verifier object used to verify host keys, to ensure that
|
47
|
+
# the connection is not being spoofed.
|
48
|
+
attr_reader :host_key_verifier
|
49
|
+
|
50
|
+
# The hash of options that were given to the object at initialization.
|
51
|
+
attr_reader :options
|
52
|
+
|
53
|
+
# Instantiates a new transport layer abstraction. This will block until
|
54
|
+
# the initial key exchange completes, leaving you with a ready-to-use
|
55
|
+
# transport session.
|
56
|
+
def initialize(host, options={})
|
57
|
+
self.logger = options[:logger]
|
58
|
+
|
59
|
+
@host = host
|
60
|
+
@port = options[:port] || DEFAULT_PORT
|
61
|
+
@options = options
|
62
|
+
|
63
|
+
debug { "establishing connection to #{@host}:#{@port}" }
|
64
|
+
factory = options[:proxy] || TCPSocket
|
65
|
+
@socket = timeout(options[:timeout] || 0) { factory.open(@host, @port) }
|
66
|
+
@socket.extend(PacketStream)
|
67
|
+
@socket.logger = @logger
|
68
|
+
|
69
|
+
debug { "connection established" }
|
70
|
+
|
71
|
+
@queue = []
|
72
|
+
|
73
|
+
@host_key_verifier = select_host_key_verifier(options[:paranoid])
|
74
|
+
|
75
|
+
@server_version = ServerVersion.new(socket, logger)
|
76
|
+
|
77
|
+
@algorithms = Algorithms.new(self, options)
|
78
|
+
wait { algorithms.initialized? }
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns the host (and possibly IP address) in a format compatible with
|
82
|
+
# SSH known-host files.
|
83
|
+
def host_as_string
|
84
|
+
@host_as_string ||= begin
|
85
|
+
string = "#{host}"
|
86
|
+
string = "[#{string}]:#{port}" if port != DEFAULT_PORT
|
87
|
+
if socket.peer_ip != host
|
88
|
+
string2 = socket.peer_ip
|
89
|
+
string2 = "[#{string2}]:#{port}" if port != DEFAULT_PORT
|
90
|
+
string << "," << string2
|
91
|
+
end
|
92
|
+
string
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Cleans up (see PacketStream#cleanup) and closes the underlying socket.
|
97
|
+
def close
|
98
|
+
socket.cleanup
|
99
|
+
socket.close
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns a new service_request packet for the given service name, ready
|
103
|
+
# for sending to the server.
|
104
|
+
def service_request(service)
|
105
|
+
Net::SSH::Buffer.from(:byte, SERVICE_REQUEST, :string, service)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Requests a rekey operation, and blocks until the operation completes.
|
109
|
+
# If a rekey is already pending, this returns immediately, having no
|
110
|
+
# effect.
|
111
|
+
def rekey!
|
112
|
+
if !algorithms.pending?
|
113
|
+
algorithms.rekey!
|
114
|
+
wait { algorithms.initialized? }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns immediately if a rekey is already in process. Otherwise, if a
|
119
|
+
# rekey is needed (as indicated by the socket, see PacketStream#if_needs_rekey?)
|
120
|
+
# one is performed, causing this method to block until it completes.
|
121
|
+
def rekey_as_needed
|
122
|
+
return if algorithms.pending?
|
123
|
+
socket.if_needs_rekey? { rekey! }
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns a hash of information about the peer (remote) side of the socket,
|
127
|
+
# including :ip, :port, :host, and :canonized (see #host_as_string).
|
128
|
+
def peer
|
129
|
+
@peer ||= { :ip => socket.peer_ip, :port => @port.to_i, :host => @host, :canonized => host_as_string }
|
130
|
+
end
|
131
|
+
|
132
|
+
# Blocks until a new packet is available to be read, and returns that
|
133
|
+
# packet. See #poll_message.
|
134
|
+
def next_message
|
135
|
+
poll_message(:block)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Tries to read the next packet from the socket. If mode is :nonblock (the
|
139
|
+
# default), this will not block and will return nil if there are no packets
|
140
|
+
# waiting to be read. Otherwise, this will block until a packet is
|
141
|
+
# available. Note that some packet types (DISCONNECT, IGNORE, UNIMPLEMENTED,
|
142
|
+
# DEBUG, and KEXINIT) are handled silently by this method, and will never
|
143
|
+
# be returned.
|
144
|
+
#
|
145
|
+
# If a key-exchange is in process and a disallowed packet type is
|
146
|
+
# received, it will be enqueued and otherwise ignored. When a key-exchange
|
147
|
+
# is not in process, and consume_queue is true, packets will be first
|
148
|
+
# read from the queue before the socket is queried.
|
149
|
+
def poll_message(mode=:nonblock, consume_queue=true)
|
150
|
+
loop do
|
151
|
+
if consume_queue && @queue.any? && algorithms.allow?(@queue.first)
|
152
|
+
return @queue.shift
|
153
|
+
end
|
154
|
+
|
155
|
+
packet = socket.next_packet(mode)
|
156
|
+
return nil if packet.nil?
|
157
|
+
|
158
|
+
case packet.type
|
159
|
+
when DISCONNECT
|
160
|
+
raise Net::SSH::Disconnect, "disconnected: #{packet[:description]} (#{packet[:reason_code]})"
|
161
|
+
|
162
|
+
when IGNORE
|
163
|
+
debug { "IGNORE packet recieved: #{packet[:data].inspect}" }
|
164
|
+
|
165
|
+
when UNIMPLEMENTED
|
166
|
+
lwarn { "UNIMPLEMENTED: #{packet[:number]}" }
|
167
|
+
|
168
|
+
when DEBUG
|
169
|
+
send(packet[:always_display] ? :fatal : :debug) { packet[:message] }
|
170
|
+
|
171
|
+
when KEXINIT
|
172
|
+
algorithms.accept_kexinit(packet)
|
173
|
+
|
174
|
+
else
|
175
|
+
return packet if algorithms.allow?(packet)
|
176
|
+
push(packet)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Waits (blocks) until the given block returns true. If no block is given,
|
182
|
+
# this just waits long enough to see if there are any pending packets. Any
|
183
|
+
# packets read are enqueued (see #push).
|
184
|
+
def wait
|
185
|
+
loop do
|
186
|
+
break if block_given? && yield
|
187
|
+
message = poll_message(:nonblock, false)
|
188
|
+
push(message) if message
|
189
|
+
break if !block_given?
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Adds the given packet to the packet queue. If the queue is non-empty,
|
194
|
+
# #poll_message will return packets from the queue in the order they
|
195
|
+
# were received.
|
196
|
+
def push(packet)
|
197
|
+
@queue.push(packet)
|
198
|
+
end
|
199
|
+
|
200
|
+
# Sends the given message via the packet stream, blocking until the
|
201
|
+
# entire message has been sent.
|
202
|
+
def send_message(message)
|
203
|
+
socket.send_packet(message)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Enqueues the given message, such that it will be sent at the earliest
|
207
|
+
# opportunity. This does not block, but returns immediately.
|
208
|
+
def enqueue_message(message)
|
209
|
+
socket.enqueue_packet(message)
|
210
|
+
end
|
211
|
+
|
212
|
+
# Configure's the packet stream's client state with the given set of
|
213
|
+
# options. This is typically used to define the cipher, compression, and
|
214
|
+
# hmac algorithms to use when sending packets to the server.
|
215
|
+
def configure_client(options={})
|
216
|
+
socket.client.set(options)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Configure's the packet stream's server state with the given set of
|
220
|
+
# options. This is typically used to define the cipher, compression, and
|
221
|
+
# hmac algorithms to use when reading packets from the server.
|
222
|
+
def configure_server(options={})
|
223
|
+
socket.server.set(options)
|
224
|
+
end
|
225
|
+
|
226
|
+
# Sets a new hint for the packet stream, which the packet stream may use
|
227
|
+
# to change its behavior. (See PacketStream#hints).
|
228
|
+
def hint(which, value=true)
|
229
|
+
socket.hints[which] = value
|
230
|
+
end
|
231
|
+
|
232
|
+
public
|
233
|
+
|
234
|
+
# this method is primarily for use in tests
|
235
|
+
attr_reader :queue #:nodoc:
|
236
|
+
|
237
|
+
private
|
238
|
+
|
239
|
+
# Instantiates a new host-key verification class, based on the value of
|
240
|
+
# the parameter. When true or nil, the default Lenient verifier is
|
241
|
+
# returned. If it is false, the Null verifier is returned, and if it is
|
242
|
+
# :very, the Strict verifier is returned. If the argument happens to
|
243
|
+
# respond to :verify, it is returned directly. Otherwise, an exception
|
244
|
+
# is raised.
|
245
|
+
def select_host_key_verifier(paranoid)
|
246
|
+
case paranoid
|
247
|
+
when true, nil then
|
248
|
+
Net::SSH::Verifiers::Lenient.new
|
249
|
+
when false then
|
250
|
+
Net::SSH::Verifiers::Null.new
|
251
|
+
when :very then
|
252
|
+
Net::SSH::Verifiers::Strict.new
|
253
|
+
else
|
254
|
+
if paranoid.respond_to?(:verify)
|
255
|
+
paranoid
|
256
|
+
else
|
257
|
+
raise ArgumentError, "argument to :paranoid is not valid: #{paranoid.inspect}"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end; end; end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
require 'net/ssh/transport/cipher_factory'
|
3
|
+
require 'net/ssh/transport/hmac'
|
4
|
+
|
5
|
+
module Net; module SSH; module Transport
|
6
|
+
|
7
|
+
# Encapsulates state information about one end of an SSH connection. Such
|
8
|
+
# state includes the packet sequence number, the algorithms in use, how
|
9
|
+
# many packets and blocks have been processed since the last reset, and so
|
10
|
+
# forth. This class will never be instantiated directly, but is used as
|
11
|
+
# part of the internal state of the PacketStream module.
|
12
|
+
class State
|
13
|
+
# The socket object that owns this state object.
|
14
|
+
attr_reader :socket
|
15
|
+
|
16
|
+
# The next packet sequence number for this socket endpoint.
|
17
|
+
attr_reader :sequence_number
|
18
|
+
|
19
|
+
# The cipher algorithm in use for this socket endpoint.
|
20
|
+
attr_reader :cipher
|
21
|
+
|
22
|
+
# The hmac algorithm in use for this endpoint.
|
23
|
+
attr_reader :hmac
|
24
|
+
|
25
|
+
# The compression algorithm in use for this endpoint.
|
26
|
+
attr_reader :compression
|
27
|
+
|
28
|
+
# The compression level to use when compressing data (or nil, for the default).
|
29
|
+
attr_reader :compression_level
|
30
|
+
|
31
|
+
# The number of packets processed since the last call to #reset!
|
32
|
+
attr_reader :packets
|
33
|
+
|
34
|
+
# The number of data blocks processed since the last call to #reset!
|
35
|
+
attr_reader :blocks
|
36
|
+
|
37
|
+
# The maximum number of packets that this endpoint wants to process before
|
38
|
+
# needing a rekey.
|
39
|
+
attr_accessor :max_packets
|
40
|
+
|
41
|
+
# The maximum number of blocks that this endpoint wants to process before
|
42
|
+
# needing a rekey.
|
43
|
+
attr_accessor :max_blocks
|
44
|
+
|
45
|
+
# The user-specified maximum number of bytes that this endpoint ought to
|
46
|
+
# process before needing a rekey.
|
47
|
+
attr_accessor :rekey_limit
|
48
|
+
|
49
|
+
# Creates a new state object, belonging to the given socket. Initializes
|
50
|
+
# the algorithms to "none".
|
51
|
+
def initialize(socket)
|
52
|
+
@socket = socket
|
53
|
+
@sequence_number = @packets = @blocks = 0
|
54
|
+
@cipher = CipherFactory.get("none")
|
55
|
+
@hmac = HMAC.get("none")
|
56
|
+
@compression = nil
|
57
|
+
@compressor = @decompressor = nil
|
58
|
+
end
|
59
|
+
|
60
|
+
# A convenience method for quickly setting multiple values in a single
|
61
|
+
# command.
|
62
|
+
def set(values)
|
63
|
+
values.each do |key, value|
|
64
|
+
instance_variable_set("@#{key}", value)
|
65
|
+
end
|
66
|
+
reset!
|
67
|
+
end
|
68
|
+
|
69
|
+
# Increments the counters. The sequence number is incremented (and remapped
|
70
|
+
# so it always fits in a 32-bit integer). The number of packets and blocks
|
71
|
+
# are also incremented.
|
72
|
+
def increment(packet_length)
|
73
|
+
@sequence_number = (@sequence_number + 1) & 0xFFFFFFFF
|
74
|
+
@packets += 1
|
75
|
+
@blocks += (packet_length + 4) / cipher.block_size
|
76
|
+
end
|
77
|
+
|
78
|
+
# The compressor object to use when compressing data. This takes into account
|
79
|
+
# the desired compression level.
|
80
|
+
def compressor
|
81
|
+
@compressor ||= Zlib::Deflate.new(compression_level || Zlib::DEFAULT_COMPRESSION)
|
82
|
+
end
|
83
|
+
|
84
|
+
# The decompressor object to use when decompressing data.
|
85
|
+
def decompressor
|
86
|
+
@decompressor ||= Zlib::Inflate.new(nil)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns true if data compression/decompression is enabled. This will
|
90
|
+
# return true if :standard compression is selected, or if :delayed
|
91
|
+
# compression is selected and the :authenticated hint has been received
|
92
|
+
# by the socket.
|
93
|
+
def compression?
|
94
|
+
compression == :standard || (compression == :delayed && socket.hints[:authenticated])
|
95
|
+
end
|
96
|
+
|
97
|
+
# Compresses the data. If no compression is in effect, this will just return
|
98
|
+
# the data unmodified, otherwise it uses #compressor to compress the data.
|
99
|
+
def compress(data)
|
100
|
+
data = data.to_s
|
101
|
+
return data unless compression?
|
102
|
+
compressor.deflate(data, Zlib::SYNC_FLUSH)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Deompresses the data. If no compression is in effect, this will just return
|
106
|
+
# the data unmodified, otherwise it uses #decompressor to decompress the data.
|
107
|
+
def decompress(data)
|
108
|
+
data = data.to_s
|
109
|
+
return data unless compression?
|
110
|
+
decompressor.inflate(data)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Resets the counters on the state object, but leaves the sequence_number
|
114
|
+
# unchanged. It also sets defaults for and recomputes the max_packets and
|
115
|
+
# max_blocks values.
|
116
|
+
def reset!
|
117
|
+
@packets = @blocks = 0
|
118
|
+
|
119
|
+
@max_packets ||= 1 << 31
|
120
|
+
|
121
|
+
if max_blocks.nil?
|
122
|
+
# cargo-culted from openssh. the idea is that "the 2^(blocksize*2)
|
123
|
+
# limit is too expensive for 3DES, blowfish, etc., so enforce a 1GB
|
124
|
+
# limit for small blocksizes."
|
125
|
+
|
126
|
+
if cipher.block_size >= 16
|
127
|
+
@max_blocks = 1 << (cipher.block_size * 2)
|
128
|
+
else
|
129
|
+
@max_blocks = (1 << 30) / cipher.block_size
|
130
|
+
end
|
131
|
+
|
132
|
+
# if a limit on the # of bytes has been given, convert that into a
|
133
|
+
# minimum number of blocks processed.
|
134
|
+
|
135
|
+
if rekey_limit
|
136
|
+
@max_blocks = [@max_blocks, rekey_limit / cipher.block_size].min
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
cleanup
|
141
|
+
end
|
142
|
+
|
143
|
+
# Closes any the compressor and/or decompressor objects that have been
|
144
|
+
# instantiated.
|
145
|
+
def cleanup
|
146
|
+
if @compressor
|
147
|
+
@compressor.finish if !@compressor.finished?
|
148
|
+
@compressor.close
|
149
|
+
end
|
150
|
+
|
151
|
+
if @decompressor
|
152
|
+
# we call reset here so that we don't get warnings when we try to
|
153
|
+
# close the decompressor
|
154
|
+
@decompressor.reset
|
155
|
+
@decompressor.close
|
156
|
+
end
|
157
|
+
|
158
|
+
@compressor = @decompressor = nil
|
159
|
+
end
|
160
|
+
|
161
|
+
# Returns true if the number of packets processed exceeds the maximum
|
162
|
+
# number of packets, or if the number of blocks processed exceeds the
|
163
|
+
# maximum number of blocks.
|
164
|
+
def needs_rekey?
|
165
|
+
max_packets && packets > max_packets ||
|
166
|
+
max_blocks && blocks > max_blocks
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
end; end; end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'net/ssh/verifiers/strict'
|
2
|
+
|
3
|
+
module Net; module SSH; module Verifiers
|
4
|
+
|
5
|
+
# Basically the same as the Strict verifier, but does not try to actually
|
6
|
+
# verify a connection if the server is the localhost and the port is a
|
7
|
+
# nonstandard port number. Those two conditions will typically mean the
|
8
|
+
# connection is being tunnelled through a forwarded port, so the known-hosts
|
9
|
+
# file will not be helpful (in general).
|
10
|
+
class Lenient < Strict
|
11
|
+
# Tries to determine if the connection is being tunnelled, and if so,
|
12
|
+
# returns true. Otherwise, performs the standard strict verification.
|
13
|
+
def verify(arguments)
|
14
|
+
return true if tunnelled?(arguments)
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# A connection is potentially being tunnelled if the port is not 22,
|
21
|
+
# and the ip refers to the localhost.
|
22
|
+
def tunnelled?(args)
|
23
|
+
return false if args[:session].port == Net::SSH::Transport::Session::DEFAULT_PORT
|
24
|
+
|
25
|
+
ip = args[:session].peer[:ip]
|
26
|
+
return ip == "127.0.0.1" || ip == "::1"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end; end; end
|