Class: Net::SSH::Transport::State

Inherits:
Object
  • Object
show all
Defined in:
lib/net/ssh/transport/state.rb

Overview

Encapsulates state information about one end of an SSH connection. Such state includes the packet sequence number, the algorithms in use, how many packets and blocks have been processed since the last reset, and so forth. This class will never be instantiated directly, but is used as part of the internal state of the PacketStream module.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(socket, role) ⇒ State

Creates a new state object, belonging to the given socket. Initializes the algorithms to “none”.



57
58
59
60
61
62
63
64
65
66
67
# File 'lib/net/ssh/transport/state.rb', line 57

def initialize(socket, role)
  @socket = socket
  @role = role
  @sequence_number = @packets = @blocks = 0
  @cipher = CipherFactory.get("none")
  @block_size = 8
  @hmac = HMAC.get("none")
  @compression = nil
  @compressor = @decompressor = nil
  @next_iv = ""
end

Instance Attribute Details

#block_sizeObject (readonly)

The block size for the cipher



38
39
40
# File 'lib/net/ssh/transport/state.rb', line 38

def block_size
  @block_size
end

#blocksObject (readonly)

The number of data blocks processed since the last call to #reset!



32
33
34
# File 'lib/net/ssh/transport/state.rb', line 32

def blocks
  @blocks
end

#cipherObject (readonly)

The cipher algorithm in use for this socket endpoint.



35
36
37
# File 'lib/net/ssh/transport/state.rb', line 35

def cipher
  @cipher
end

#compressionObject (readonly)

The compression algorithm in use for this endpoint.



23
24
25
# File 'lib/net/ssh/transport/state.rb', line 23

def compression
  @compression
end

#compression_levelObject (readonly)

The compression level to use when compressing data (or nil, for the default).



26
27
28
# File 'lib/net/ssh/transport/state.rb', line 26

def compression_level
  @compression_level
end

#hmacObject (readonly)

The hmac algorithm in use for this endpoint.



20
21
22
# File 'lib/net/ssh/transport/state.rb', line 20

def hmac
  @hmac
end

#max_blocksObject

The maximum number of blocks that this endpoint wants to process before needing a rekey.



49
50
51
# File 'lib/net/ssh/transport/state.rb', line 49

def max_blocks
  @max_blocks
end

#max_packetsObject

The maximum number of packets that this endpoint wants to process before needing a rekey.



45
46
47
# File 'lib/net/ssh/transport/state.rb', line 45

def max_packets
  @max_packets
end

#packetsObject (readonly)

The number of packets processed since the last call to #reset!



29
30
31
# File 'lib/net/ssh/transport/state.rb', line 29

def packets
  @packets
end

#rekey_limitObject

The user-specified maximum number of bytes that this endpoint ought to process before needing a rekey.



53
54
55
# File 'lib/net/ssh/transport/state.rb', line 53

def rekey_limit
  @rekey_limit
end

#roleObject (readonly)

The role that this state plays (either :client or :server)



41
42
43
# File 'lib/net/ssh/transport/state.rb', line 41

def role
  @role
end

#sequence_numberObject (readonly)

The next packet sequence number for this socket endpoint.



17
18
19
# File 'lib/net/ssh/transport/state.rb', line 17

def sequence_number
  @sequence_number
end

#socketObject (readonly)

The socket object that owns this state object.



14
15
16
# File 'lib/net/ssh/transport/state.rb', line 14

def socket
  @socket
end

Instance Method Details

#cleanupObject

Closes any the compressor and/or decompressor objects that have been instantiated.



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/net/ssh/transport/state.rb', line 167

def cleanup
  if @compressor
    @compressor.finish if !@compressor.finished?
    @compressor.close
  end

  if @decompressor
    # we call reset here so that we don't get warnings when we try to
    # close the decompressor
    @decompressor.reset
    @decompressor.close
  end

  @compressor = @decompressor = nil
end

#compress(data) ⇒ Object

Compresses the data. If no compression is in effect, this will just return the data unmodified, otherwise it uses #compressor to compress the data.



120
121
122
123
124
# File 'lib/net/ssh/transport/state.rb', line 120

def compress(data)
  data = data.to_s
  return data unless compression?
  compressor.deflate(data, Zlib::SYNC_FLUSH)
end

#compression?Boolean

Returns true if data compression/decompression is enabled. This will return true if :standard compression is selected, or if :delayed compression is selected and the :authenticated hint has been received by the socket.

Returns:

  • (Boolean)


114
115
116
# File 'lib/net/ssh/transport/state.rb', line 114

def compression?
  compression == :standard || (compression == :delayed && socket.hints[:authenticated])
end

#compressorObject

The compressor object to use when compressing data. This takes into account the desired compression level.



101
102
103
# File 'lib/net/ssh/transport/state.rb', line 101

def compressor
  @compressor ||= Zlib::Deflate.new(compression_level || Zlib::DEFAULT_COMPRESSION)
end

#decompress(data) ⇒ Object

Deompresses the data. If no compression is in effect, this will just return the data unmodified, otherwise it uses #decompressor to decompress the data.



128
129
130
131
132
# File 'lib/net/ssh/transport/state.rb', line 128

def decompress(data)
  data = data.to_s
  return data unless compression?
  decompressor.inflate(data)
end

#decompressorObject

The decompressor object to use when decompressing data.



106
107
108
# File 'lib/net/ssh/transport/state.rb', line 106

def decompressor
  @decompressor ||= Zlib::Inflate.new(nil)
end

#final_cipherObject



84
85
86
87
88
# File 'lib/net/ssh/transport/state.rb', line 84

def final_cipher
  result = cipher.final
  update_next_iv(role == :client ? result : "", true)
  return result
end

#increment(packet_length) ⇒ Object

Increments the counters. The sequence number is incremented (and remapped so it always fits in a 32-bit integer). The number of packets and blocks are also incremented.



93
94
95
96
97
# File 'lib/net/ssh/transport/state.rb', line 93

def increment(packet_length)
  @sequence_number = (@sequence_number + 1) & 0xFFFFFFFF
  @packets += 1
  @blocks += (packet_length + 4) / @block_size
end

#needs_rekey?Boolean

Returns true if the number of packets processed exceeds the maximum number of packets, or if the number of blocks processed exceeds the maximum number of blocks.

Returns:

  • (Boolean)


186
187
188
189
# File 'lib/net/ssh/transport/state.rb', line 186

def needs_rekey?
  max_packets && packets > max_packets ||
  max_blocks && blocks > max_blocks
end

#reset!Object

Resets the counters on the state object, but leaves the sequence_number unchanged. It also sets defaults for and recomputes the max_packets and max_blocks values.



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/net/ssh/transport/state.rb', line 137

def reset!
  @packets = @blocks = 0

  @max_packets ||= 1 << 31

  @block_size = cipher.name == "RC4" ? 8 : cipher.block_size

  if max_blocks.nil?
    # cargo-culted from openssh. the idea is that "the 2^(blocksize*2)
    # limit is too expensive for 3DES, blowfish, etc., so enforce a 1GB
    # limit for small blocksizes."
    if @block_size >= 16
      @max_blocks = 1 << (@block_size * 2)
    else
      @max_blocks = (1 << 30) / @block_size
    end

    # if a limit on the # of bytes has been given, convert that into a
    # minimum number of blocks processed.

    if rekey_limit
      @max_blocks = [@max_blocks, rekey_limit / @block_size].min
    end
  end

  cleanup
end

#set(values) ⇒ Object

A convenience method for quickly setting multiple values in a single command.



71
72
73
74
75
76
# File 'lib/net/ssh/transport/state.rb', line 71

def set(values)
  values.each do |key, value|
    instance_variable_set("@#{key}", value)
  end
  reset!
end

#update_cipher(data) ⇒ Object



78
79
80
81
82
# File 'lib/net/ssh/transport/state.rb', line 78

def update_cipher(data)
  result = cipher.update(data)
  update_next_iv(role == :client ? result : data)
  return result
end