net-ssh 4.1.0 → 6.1.0
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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +8 -2
- data/.rubocop_todo.yml +405 -552
- data/.travis.yml +23 -22
- data/CHANGES.txt +112 -1
- data/Gemfile +1 -7
- data/{Gemfile.norbnacl → Gemfile.noed25519} +1 -1
- data/Manifest +4 -5
- data/README.md +287 -0
- data/Rakefile +40 -29
- data/appveyor.yml +12 -6
- data/lib/net/ssh.rb +68 -32
- data/lib/net/ssh/authentication/agent.rb +234 -222
- data/lib/net/ssh/authentication/certificate.rb +175 -164
- data/lib/net/ssh/authentication/constants.rb +17 -14
- data/lib/net/ssh/authentication/ed25519.rb +162 -141
- data/lib/net/ssh/authentication/ed25519_loader.rb +32 -29
- data/lib/net/ssh/authentication/key_manager.rb +40 -9
- data/lib/net/ssh/authentication/methods/abstract.rb +53 -47
- data/lib/net/ssh/authentication/methods/hostbased.rb +32 -33
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +1 -1
- data/lib/net/ssh/authentication/methods/none.rb +10 -10
- data/lib/net/ssh/authentication/methods/password.rb +13 -13
- data/lib/net/ssh/authentication/methods/publickey.rb +56 -55
- data/lib/net/ssh/authentication/pageant.rb +468 -465
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
- data/lib/net/ssh/authentication/session.rb +130 -122
- data/lib/net/ssh/buffer.rb +345 -312
- data/lib/net/ssh/buffered_io.rb +163 -163
- data/lib/net/ssh/config.rb +316 -238
- data/lib/net/ssh/connection/channel.rb +670 -650
- data/lib/net/ssh/connection/constants.rb +30 -26
- data/lib/net/ssh/connection/event_loop.rb +108 -105
- data/lib/net/ssh/connection/keepalive.rb +54 -50
- data/lib/net/ssh/connection/session.rb +682 -671
- data/lib/net/ssh/connection/term.rb +180 -176
- data/lib/net/ssh/errors.rb +101 -99
- data/lib/net/ssh/key_factory.rb +195 -108
- data/lib/net/ssh/known_hosts.rb +161 -152
- data/lib/net/ssh/loggable.rb +57 -55
- data/lib/net/ssh/packet.rb +82 -78
- data/lib/net/ssh/prompt.rb +55 -53
- data/lib/net/ssh/proxy/command.rb +104 -89
- data/lib/net/ssh/proxy/errors.rb +12 -8
- data/lib/net/ssh/proxy/http.rb +93 -91
- data/lib/net/ssh/proxy/https.rb +42 -39
- data/lib/net/ssh/proxy/jump.rb +50 -47
- data/lib/net/ssh/proxy/socks4.rb +0 -2
- data/lib/net/ssh/proxy/socks5.rb +11 -12
- data/lib/net/ssh/service/forward.rb +370 -317
- data/lib/net/ssh/test.rb +83 -77
- data/lib/net/ssh/test/channel.rb +146 -142
- data/lib/net/ssh/test/extensions.rb +150 -146
- data/lib/net/ssh/test/kex.rb +35 -31
- data/lib/net/ssh/test/local_packet.rb +48 -44
- data/lib/net/ssh/test/packet.rb +87 -84
- data/lib/net/ssh/test/remote_packet.rb +35 -31
- data/lib/net/ssh/test/script.rb +173 -171
- data/lib/net/ssh/test/socket.rb +59 -55
- data/lib/net/ssh/transport/algorithms.rb +430 -364
- data/lib/net/ssh/transport/cipher_factory.rb +95 -91
- data/lib/net/ssh/transport/constants.rb +33 -25
- data/lib/net/ssh/transport/ctr.rb +33 -11
- data/lib/net/ssh/transport/hmac.rb +15 -13
- data/lib/net/ssh/transport/hmac/abstract.rb +82 -63
- data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/identity_cipher.rb +55 -51
- data/lib/net/ssh/transport/kex.rb +14 -13
- data/lib/net/ssh/transport/kex/abstract.rb +123 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +38 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +112 -217
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -62
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
- data/lib/net/ssh/transport/key_expander.rb +29 -25
- data/lib/net/ssh/transport/openssl.rb +116 -116
- data/lib/net/ssh/transport/packet_stream.rb +223 -190
- data/lib/net/ssh/transport/server_version.rb +64 -66
- data/lib/net/ssh/transport/session.rb +306 -257
- data/lib/net/ssh/transport/state.rb +198 -196
- data/lib/net/ssh/verifiers/accept_new.rb +35 -0
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +34 -0
- data/lib/net/ssh/verifiers/always.rb +56 -0
- data/lib/net/ssh/verifiers/never.rb +21 -0
- data/lib/net/ssh/version.rb +55 -53
- data/net-ssh-public_cert.pem +18 -19
- data/net-ssh.gemspec +12 -11
- data/support/ssh_tunnel_bug.rb +2 -2
- metadata +86 -75
- metadata.gz.sig +0 -0
- data/Gemfile.norbnacl.lock +0 -41
- data/README.rdoc +0 -169
- data/lib/net/ssh/ruby_compat.rb +0 -24
- data/lib/net/ssh/verifiers/lenient.rb +0 -30
- data/lib/net/ssh/verifiers/null.rb +0 -12
- data/lib/net/ssh/verifiers/secure.rb +0 -52
- data/lib/net/ssh/verifiers/strict.rb +0 -24
- data/support/arcfour_check.rb +0 -20
@@ -2,205 +2,207 @@ require 'zlib'
|
|
2
2
|
require 'net/ssh/transport/cipher_factory'
|
3
3
|
require 'net/ssh/transport/hmac'
|
4
4
|
|
5
|
-
module Net
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
# A convenience method for quickly setting multiple values in a single
|
70
|
-
# command.
|
71
|
-
def set(values)
|
72
|
-
values.each do |key, value|
|
73
|
-
instance_variable_set("@#{key}", value)
|
74
|
-
end
|
75
|
-
reset!
|
76
|
-
end
|
77
|
-
|
78
|
-
def update_cipher(data)
|
79
|
-
result = cipher.update(data)
|
80
|
-
update_next_iv(role == :client ? result : data)
|
81
|
-
return result
|
82
|
-
end
|
83
|
-
|
84
|
-
def final_cipher
|
85
|
-
result = cipher.final
|
86
|
-
update_next_iv(role == :client ? result : "", true)
|
87
|
-
return result
|
88
|
-
end
|
89
|
-
|
90
|
-
# Increments the counters. The sequence number is incremented (and remapped
|
91
|
-
# so it always fits in a 32-bit integer). The number of packets and blocks
|
92
|
-
# are also incremented.
|
93
|
-
def increment(packet_length)
|
94
|
-
@sequence_number = (@sequence_number + 1) & 0xFFFFFFFF
|
95
|
-
@packets += 1
|
96
|
-
@blocks += (packet_length + 4) / @block_size
|
97
|
-
end
|
98
|
-
|
99
|
-
# The compressor object to use when compressing data. This takes into account
|
100
|
-
# the desired compression level.
|
101
|
-
def compressor
|
102
|
-
@compressor ||= Zlib::Deflate.new(compression_level || Zlib::DEFAULT_COMPRESSION)
|
103
|
-
end
|
104
|
-
|
105
|
-
# The decompressor object to use when decompressing data.
|
106
|
-
def decompressor
|
107
|
-
@decompressor ||= Zlib::Inflate.new(nil)
|
108
|
-
end
|
109
|
-
|
110
|
-
# Returns true if data compression/decompression is enabled. This will
|
111
|
-
# return true if :standard compression is selected, or if :delayed
|
112
|
-
# compression is selected and the :authenticated hint has been received
|
113
|
-
# by the socket.
|
114
|
-
def compression?
|
115
|
-
compression == :standard || (compression == :delayed && socket.hints[:authenticated])
|
116
|
-
end
|
117
|
-
|
118
|
-
# Compresses the data. If no compression is in effect, this will just return
|
119
|
-
# the data unmodified, otherwise it uses #compressor to compress the data.
|
120
|
-
def compress(data)
|
121
|
-
data = data.to_s
|
122
|
-
return data unless compression?
|
123
|
-
compressor.deflate(data, Zlib::SYNC_FLUSH)
|
124
|
-
end
|
125
|
-
|
126
|
-
# Deompresses the data. If no compression is in effect, this will just return
|
127
|
-
# the data unmodified, otherwise it uses #decompressor to decompress the data.
|
128
|
-
def decompress(data)
|
129
|
-
data = data.to_s
|
130
|
-
return data unless compression?
|
131
|
-
decompressor.inflate(data)
|
132
|
-
end
|
133
|
-
|
134
|
-
# Resets the counters on the state object, but leaves the sequence_number
|
135
|
-
# unchanged. It also sets defaults for and recomputes the max_packets and
|
136
|
-
# max_blocks values.
|
137
|
-
def reset!
|
138
|
-
@packets = @blocks = 0
|
139
|
-
|
140
|
-
@max_packets ||= 1 << 31
|
141
|
-
|
142
|
-
@block_size = cipher.name == "RC4" ? 8 : cipher.block_size
|
143
|
-
|
144
|
-
if max_blocks.nil?
|
145
|
-
# cargo-culted from openssh. the idea is that "the 2^(blocksize*2)
|
146
|
-
# limit is too expensive for 3DES, blowfish, etc., so enforce a 1GB
|
147
|
-
# limit for small blocksizes."
|
148
|
-
if @block_size >= 16
|
149
|
-
@max_blocks = 1 << (@block_size * 2)
|
150
|
-
else
|
151
|
-
@max_blocks = (1 << 30) / @block_size
|
5
|
+
module Net
|
6
|
+
module SSH
|
7
|
+
module Transport
|
8
|
+
|
9
|
+
# Encapsulates state information about one end of an SSH connection. Such
|
10
|
+
# state includes the packet sequence number, the algorithms in use, how
|
11
|
+
# many packets and blocks have been processed since the last reset, and so
|
12
|
+
# forth. This class will never be instantiated directly, but is used as
|
13
|
+
# part of the internal state of the PacketStream module.
|
14
|
+
class State
|
15
|
+
# The socket object that owns this state object.
|
16
|
+
attr_reader :socket
|
17
|
+
|
18
|
+
# The next packet sequence number for this socket endpoint.
|
19
|
+
attr_reader :sequence_number
|
20
|
+
|
21
|
+
# The hmac algorithm in use for this endpoint.
|
22
|
+
attr_reader :hmac
|
23
|
+
|
24
|
+
# The compression algorithm in use for this endpoint.
|
25
|
+
attr_reader :compression
|
26
|
+
|
27
|
+
# The compression level to use when compressing data (or nil, for the default).
|
28
|
+
attr_reader :compression_level
|
29
|
+
|
30
|
+
# The number of packets processed since the last call to #reset!
|
31
|
+
attr_reader :packets
|
32
|
+
|
33
|
+
# The number of data blocks processed since the last call to #reset!
|
34
|
+
attr_reader :blocks
|
35
|
+
|
36
|
+
# The cipher algorithm in use for this socket endpoint.
|
37
|
+
attr_reader :cipher
|
38
|
+
|
39
|
+
# The block size for the cipher
|
40
|
+
attr_reader :block_size
|
41
|
+
|
42
|
+
# The role that this state plays (either :client or :server)
|
43
|
+
attr_reader :role
|
44
|
+
|
45
|
+
# The maximum number of packets that this endpoint wants to process before
|
46
|
+
# needing a rekey.
|
47
|
+
attr_accessor :max_packets
|
48
|
+
|
49
|
+
# The maximum number of blocks that this endpoint wants to process before
|
50
|
+
# needing a rekey.
|
51
|
+
attr_accessor :max_blocks
|
52
|
+
|
53
|
+
# The user-specified maximum number of bytes that this endpoint ought to
|
54
|
+
# process before needing a rekey.
|
55
|
+
attr_accessor :rekey_limit
|
56
|
+
|
57
|
+
# Creates a new state object, belonging to the given socket. Initializes
|
58
|
+
# the algorithms to "none".
|
59
|
+
def initialize(socket, role)
|
60
|
+
@socket = socket
|
61
|
+
@role = role
|
62
|
+
@sequence_number = @packets = @blocks = 0
|
63
|
+
@cipher = CipherFactory.get("none")
|
64
|
+
@block_size = 8
|
65
|
+
@hmac = HMAC.get("none")
|
66
|
+
@compression = nil
|
67
|
+
@compressor = @decompressor = nil
|
68
|
+
@next_iv = ""
|
152
69
|
end
|
153
|
-
|
154
|
-
#
|
155
|
-
#
|
156
|
-
|
157
|
-
|
158
|
-
|
70
|
+
|
71
|
+
# A convenience method for quickly setting multiple values in a single
|
72
|
+
# command.
|
73
|
+
def set(values)
|
74
|
+
values.each do |key, value|
|
75
|
+
instance_variable_set("@#{key}", value)
|
76
|
+
end
|
77
|
+
reset!
|
78
|
+
end
|
79
|
+
|
80
|
+
def update_cipher(data)
|
81
|
+
result = cipher.update(data)
|
82
|
+
update_next_iv(role == :client ? result : data)
|
83
|
+
return result
|
84
|
+
end
|
85
|
+
|
86
|
+
def final_cipher
|
87
|
+
result = cipher.final
|
88
|
+
update_next_iv(role == :client ? result : "", true)
|
89
|
+
return result
|
90
|
+
end
|
91
|
+
|
92
|
+
# Increments the counters. The sequence number is incremented (and remapped
|
93
|
+
# so it always fits in a 32-bit integer). The number of packets and blocks
|
94
|
+
# are also incremented.
|
95
|
+
def increment(packet_length)
|
96
|
+
@sequence_number = (@sequence_number + 1) & 0xFFFFFFFF
|
97
|
+
@packets += 1
|
98
|
+
@blocks += (packet_length + 4) / @block_size
|
99
|
+
end
|
100
|
+
|
101
|
+
# The compressor object to use when compressing data. This takes into account
|
102
|
+
# the desired compression level.
|
103
|
+
def compressor
|
104
|
+
@compressor ||= Zlib::Deflate.new(compression_level || Zlib::DEFAULT_COMPRESSION)
|
105
|
+
end
|
106
|
+
|
107
|
+
# The decompressor object to use when decompressing data.
|
108
|
+
def decompressor
|
109
|
+
@decompressor ||= Zlib::Inflate.new(nil)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns true if data compression/decompression is enabled. This will
|
113
|
+
# return true if :standard compression is selected, or if :delayed
|
114
|
+
# compression is selected and the :authenticated hint has been received
|
115
|
+
# by the socket.
|
116
|
+
def compression?
|
117
|
+
compression == :standard || (compression == :delayed && socket.hints[:authenticated])
|
118
|
+
end
|
119
|
+
|
120
|
+
# Compresses the data. If no compression is in effect, this will just return
|
121
|
+
# the data unmodified, otherwise it uses #compressor to compress the data.
|
122
|
+
def compress(data)
|
123
|
+
data = data.to_s
|
124
|
+
return data unless compression?
|
125
|
+
compressor.deflate(data, Zlib::SYNC_FLUSH)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Deompresses the data. If no compression is in effect, this will just return
|
129
|
+
# the data unmodified, otherwise it uses #decompressor to decompress the data.
|
130
|
+
def decompress(data)
|
131
|
+
data = data.to_s
|
132
|
+
return data unless compression?
|
133
|
+
decompressor.inflate(data)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Resets the counters on the state object, but leaves the sequence_number
|
137
|
+
# unchanged. It also sets defaults for and recomputes the max_packets and
|
138
|
+
# max_blocks values.
|
139
|
+
def reset!
|
140
|
+
@packets = @blocks = 0
|
141
|
+
|
142
|
+
@max_packets ||= 1 << 31
|
143
|
+
|
144
|
+
@block_size = cipher.block_size
|
145
|
+
|
146
|
+
if max_blocks.nil?
|
147
|
+
# cargo-culted from openssh. the idea is that "the 2^(blocksize*2)
|
148
|
+
# limit is too expensive for 3DES, blowfish, etc., so enforce a 1GB
|
149
|
+
# limit for small blocksizes."
|
150
|
+
if @block_size >= 16
|
151
|
+
@max_blocks = 1 << (@block_size * 2)
|
152
|
+
else
|
153
|
+
@max_blocks = (1 << 30) / @block_size
|
154
|
+
end
|
155
|
+
|
156
|
+
# if a limit on the # of bytes has been given, convert that into a
|
157
|
+
# minimum number of blocks processed.
|
158
|
+
|
159
|
+
@max_blocks = [@max_blocks, rekey_limit / @block_size].min if rekey_limit
|
160
|
+
end
|
161
|
+
|
162
|
+
cleanup
|
163
|
+
end
|
164
|
+
|
165
|
+
# Closes any the compressor and/or decompressor objects that have been
|
166
|
+
# instantiated.
|
167
|
+
def cleanup
|
168
|
+
if @compressor
|
169
|
+
@compressor.finish if !@compressor.finished?
|
170
|
+
@compressor.close
|
171
|
+
end
|
172
|
+
|
173
|
+
if @decompressor
|
174
|
+
# we call reset here so that we don't get warnings when we try to
|
175
|
+
# close the decompressor
|
176
|
+
@decompressor.reset
|
177
|
+
@decompressor.close
|
178
|
+
end
|
179
|
+
|
180
|
+
@compressor = @decompressor = nil
|
181
|
+
end
|
182
|
+
|
183
|
+
# Returns true if the number of packets processed exceeds the maximum
|
184
|
+
# number of packets, or if the number of blocks processed exceeds the
|
185
|
+
# maximum number of blocks.
|
186
|
+
def needs_rekey?
|
187
|
+
max_packets && packets > max_packets ||
|
188
|
+
max_blocks && blocks > max_blocks
|
189
|
+
end
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
def update_next_iv(data, reset=false)
|
194
|
+
@next_iv << data
|
195
|
+
@next_iv = @next_iv[@next_iv.size - cipher.iv_len..-1]
|
196
|
+
|
197
|
+
if reset
|
198
|
+
cipher.reset
|
199
|
+
cipher.iv = @next_iv
|
200
|
+
end
|
201
|
+
|
202
|
+
return data
|
159
203
|
end
|
160
204
|
end
|
161
205
|
|
162
|
-
cleanup
|
163
|
-
end
|
164
|
-
|
165
|
-
# Closes any the compressor and/or decompressor objects that have been
|
166
|
-
# instantiated.
|
167
|
-
def cleanup
|
168
|
-
if @compressor
|
169
|
-
@compressor.finish if !@compressor.finished?
|
170
|
-
@compressor.close
|
171
|
-
end
|
172
|
-
|
173
|
-
if @decompressor
|
174
|
-
# we call reset here so that we don't get warnings when we try to
|
175
|
-
# close the decompressor
|
176
|
-
@decompressor.reset
|
177
|
-
@decompressor.close
|
178
|
-
end
|
179
|
-
|
180
|
-
@compressor = @decompressor = nil
|
181
|
-
end
|
182
|
-
|
183
|
-
# Returns true if the number of packets processed exceeds the maximum
|
184
|
-
# number of packets, or if the number of blocks processed exceeds the
|
185
|
-
# maximum number of blocks.
|
186
|
-
def needs_rekey?
|
187
|
-
max_packets && packets > max_packets ||
|
188
|
-
max_blocks && blocks > max_blocks
|
189
206
|
end
|
190
|
-
|
191
|
-
private
|
192
|
-
|
193
|
-
def update_next_iv(data, reset=false)
|
194
|
-
@next_iv << data
|
195
|
-
@next_iv = @next_iv[@next_iv.size-cipher.iv_len..-1]
|
196
|
-
|
197
|
-
if reset
|
198
|
-
cipher.reset
|
199
|
-
cipher.iv = @next_iv
|
200
|
-
end
|
201
|
-
|
202
|
-
return data
|
203
|
-
end
|
204
207
|
end
|
205
|
-
|
206
|
-
end; end; end
|
208
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'net/ssh/errors'
|
2
|
+
require 'net/ssh/known_hosts'
|
3
|
+
require 'net/ssh/verifiers/always'
|
4
|
+
|
5
|
+
module Net
|
6
|
+
module SSH
|
7
|
+
module Verifiers
|
8
|
+
|
9
|
+
# Does a strict host verification, looking the server up in the known
|
10
|
+
# host files to see if a key has already been seen for this server. If this
|
11
|
+
# server does not appear in any host file, this will silently add the
|
12
|
+
# server. If the server does appear at least once, but the key given does
|
13
|
+
# not match any known for the server, an exception will be raised (HostKeyMismatch).
|
14
|
+
# Otherwise, this returns true.
|
15
|
+
class AcceptNew < Always
|
16
|
+
def verify(arguments)
|
17
|
+
begin
|
18
|
+
super
|
19
|
+
rescue HostKeyUnknown => err
|
20
|
+
err.remember_host!
|
21
|
+
return true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def verify_signature(&block)
|
26
|
+
yield
|
27
|
+
rescue HostKeyUnknown => err
|
28
|
+
err.remember_host!
|
29
|
+
return true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'net/ssh/verifiers/accept_new'
|
2
|
+
|
3
|
+
module Net
|
4
|
+
module SSH
|
5
|
+
module Verifiers
|
6
|
+
|
7
|
+
# Basically the same as the AcceptNew verifier, but does not try to actually
|
8
|
+
# verify a connection if the server is the localhost and the port is a
|
9
|
+
# nonstandard port number. Those two conditions will typically mean the
|
10
|
+
# connection is being tunnelled through a forwarded port, so the known-hosts
|
11
|
+
# file will not be helpful (in general).
|
12
|
+
class AcceptNewOrLocalTunnel < AcceptNew
|
13
|
+
# Tries to determine if the connection is being tunnelled, and if so,
|
14
|
+
# returns true. Otherwise, performs the standard strict verification.
|
15
|
+
def verify(arguments)
|
16
|
+
return true if tunnelled?(arguments)
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# A connection is potentially being tunnelled if the port is not 22,
|
23
|
+
# and the ip refers to the localhost.
|
24
|
+
def tunnelled?(args)
|
25
|
+
return false if args[:session].port == Net::SSH::Transport::Session::DEFAULT_PORT
|
26
|
+
|
27
|
+
ip = args[:session].peer[:ip]
|
28
|
+
return ip == "127.0.0.1" || ip == "::1"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|