Module: Net::SSH::Transport::PacketStream

### Home Classes Methods

### In Files

- lib/net/ssh/transport/packet_stream.rb

### Methods

- ::extended
- #available_for_read?
- #cleanup
- #client_name
- #enqueue_packet
- #if_needs_rekey?
- #initialize_ssh
- #next_packet
- #peer_ip
- #poll_next_packet
- #send_packet

### Included Modules

- BufferedIo

### Files

- README.rdoc

### Class/Module Index

Quicksearch

- Net
- Net::SSH
- Net::SSH::Authentication
- Net::SSH::Authentication::Agent
- Net::SSH::Authentication::Agent::Comment
- Net::SSH::Authentication::AgentError
- Net::SSH::Authentication::AgentNotAvailable
- Net::SSH::Authentication::Constants
- Net::SSH::Authentication::DisallowedMethod
- Net::SSH::Authentication::KeyManager
- Net::SSH::Authentication::KeyManagerError
- Net::SSH::Authentication::Methods
- Net::SSH::Authentication::Methods::Abstract
- Net::SSH::Authentication::Methods::Hostbased
- Net::SSH::Authentication::Methods::KeyboardInteractive
- Net::SSH::Authentication::Methods::None
- Net::SSH::Authentication::Methods::Password
- Net::SSH::Authentication::Methods::Publickey
- Net::SSH::Authentication::Session
- Net::SSH::AuthenticationFailed
- Net::SSH::Buffer
- Net::SSH::ChannelOpenFailed
- Net::SSH::ChannelRequestFailed
- Net::SSH::Compat
- Net::SSH::Config
- Net::SSH::Connection
- Net::SSH::Connection::Channel
- Net::SSH::Connection::Constants
- Net::SSH::Connection::Keepalive
- Net::SSH::Connection::Session
- Net::SSH::Connection::Session::NilChannel
- Net::SSH::Connection::Term
- Net::SSH::ConnectionTimeout
- Net::SSH::Disconnect
- Net::SSH::Exception
- Net::SSH::HostKeyError
- Net::SSH::HostKeyMismatch
- Net::SSH::HostKeyUnknown
- Net::SSH::KeyFactory
- Net::SSH::KnownHosts
- Net::SSH::Loggable
- Net::SSH::Packet
- Net::SSH::PromptMethods
- Net::SSH::PromptMethods::Clear
- Net::SSH::PromptMethods::Highline
- Net::SSH::PromptMethods::Termios
- Net::SSH::Proxy
- Net::SSH::Proxy::Command
- Net::SSH::Proxy::ConnectError
- Net::SSH::Proxy::Error
- Net::SSH::Proxy::HTTP
- Net::SSH::Proxy::SOCKS4
- Net::SSH::Proxy::SOCKS5
- Net::SSH::Proxy::UnauthorizedError
- Net::SSH::Test
- Net::SSH::Test::Channel
- Net::SSH::Test::Extensions
- Net::SSH::Test::Extensions::BufferedIo
- Net::SSH::Test::Extensions::Channel
- Net::SSH::Test::Extensions::IO
- Net::SSH::Test::Extensions::IO::ClassMethods
- Net::SSH::Test::Extensions::PacketStream
- Net::SSH::Test::Kex
- Net::SSH::Test::LocalPacket
- Net::SSH::Test::Packet
- Net::SSH::Test::RemotePacket
- Net::SSH::Test::Script
- Net::SSH::Test::Socket
- Net::SSH::Timeout
- Net::SSH::Transport
- Net::SSH::Transport::Algorithms
- Net::SSH::Transport::CTR
- Net::SSH::Transport::CipherFactory
- Net::SSH::Transport::Constants
- Net::SSH::Transport::HMAC
- Net::SSH::Transport::HMAC::Abstract
- Net::SSH::Transport::HMAC::MD5
- Net::SSH::Transport::HMAC::MD5_96
- Net::SSH::Transport::HMAC::None
- Net::SSH::Transport::HMAC::RIPEMD160
- Net::SSH::Transport::HMAC::SHA1
- Net::SSH::Transport::HMAC::SHA1_96
- Net::SSH::Transport::HMAC::SHA2_256
- Net::SSH::Transport::HMAC::SHA2_256_96
- Net::SSH::Transport::HMAC::SHA2_512
- Net::SSH::Transport::HMAC::SHA2_512_96
- Net::SSH::Transport::IdentityCipher
- Net::SSH::Transport::Kex
- Net::SSH::Transport::Kex::DiffieHellmanGroup14SHA1
- Net::SSH::Transport::Kex::DiffieHellmanGroup1SHA1
- Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA1
- Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA256
- Net::SSH::Transport::Kex::EcdhSHA2NistP256
- Net::SSH::Transport::Kex::EcdhSHA2NistP384
- Net::SSH::Transport::Kex::EcdhSHA2NistP521
- Net::SSH::Transport::KeyExpander
- Net::SSH::Transport::PacketStream
- Net::SSH::Transport::ServerVersion
- Net::SSH::Transport::Session
- Net::SSH::Transport::State
- Net::SSH::Verifiers
- Net::SSH::Verifiers::Lenient
- Net::SSH::Verifiers::Null
- Net::SSH::Verifiers::Secure
- Net::SSH::Verifiers::Strict
- Net::SSH::Version
- OpenSSL
- OpenSSL::BN
- OpenSSL::PKey
- OpenSSL::PKey::DH
- OpenSSL::PKey::DSA
- OpenSSL::PKey::EC
- OpenSSL::PKey::OpenSSL
- OpenSSL::PKey::OpenSSL::PKey
- OpenSSL::PKey::OpenSSL::PKey::OpenSSL
- OpenSSL::PKey::OpenSSL::PKey::OpenSSL::PKey
- OpenSSL::PKey::OpenSSL::PKey::OpenSSL::PKey::ECError
- OpenSSL::PKey::PKey
- OpenSSL::PKey::RSA
- String

No matching classes.

# Net::SSH::Transport::PacketStream

A module that builds additional functionality onto the Net::SSH::BufferedIo module. It adds SSH encryption, compression, and packet validation, as per the SSH2 protocol. It also adds an abstraction for polling packets, to allow for both blocking and non-blocking reads.

### Constants

PROXY_COMMAND_HOST_IP

### Attributes

client[R]

The client state object, which encapsulates the algorithms used to build packets to send to the server.

hints[R]

The map of "hints" that can be used to modify the behavior of the packet stream. For instance, when authentication succeeds, an "authenticated" hint is set, which is used to determine whether or not to compress the data when using the "delayed" compression algorithm.

server[R]

The server state object, which encapsulates the algorithms used to interpret packets coming from the server.

### Public Class Methods

extended(object) click to toggle source

    # File lib/net/ssh/transport/packet_stream.rb, line 21
    def self.extended(object)
      object.__send__(:initialize_ssh)
    end

### Public Instance Methods

available_for_read?() click to toggle source

Returns true if the IO is available for reading, and false otherwise.

    # File lib/net/ssh/transport/packet_stream.rb, line 74
    def available_for_read?
      result = Net::SSH::Compat.io_select([self], nil, nil, 0)
      result && result.first.any?
    end

cleanup() click to toggle source

Performs any pending cleanup necessary on the IO and its associated state objects. (See State#cleanup).

    # File lib/net/ssh/transport/packet_stream.rb, line 161
    def cleanup
      client.cleanup
      server.cleanup
    end

client_name() click to toggle source

The name of the client (local) end of the socket, as reported by the socket.

    # File lib/net/ssh/transport/packet_stream.rb, line 41
    def client_name
      @client_name ||= begin
        sockaddr = getsockname
        begin
          Socket.getnameinfo(sockaddr, Socket::NI_NAMEREQD).first
        rescue
          begin
            Socket.getnameinfo(sockaddr).first
          rescue
            begin
              Socket.gethostbyname(Socket.gethostname).first
            rescue
              lwarn { "the client ipaddr/name could not be determined" }
              "unknown"
            end
          end
        end
      end
    end

enqueue_packet(payload) click to toggle source

Enqueues a packet to be sent, but does not immediately send the packet. The given payload is pre-processed according to the algorithms specified in the client state (compression, cipher, and hmac).

    # File lib/net/ssh/transport/packet_stream.rb, line 124
    def enqueue_packet(payload)
      # try to compress the packet
      payload = client.compress(payload)

      # the length of the packet, minus the padding
      actual_length = 4 + payload.bytesize + 1

      # compute the padding length
      padding_length = client.block_size - (actual_length % client.block_size)
      padding_length += client.block_size if padding_length < 4

      # compute the packet length (sans the length field itself)
      packet_length = payload.bytesize + padding_length + 1

      if packet_length < 16
        padding_length += client.block_size
        packet_length = payload.bytesize + padding_length + 1
      end

      padding = Array.new(padding_length) { rand(256) }.pack("C*")

      unencrypted_data = [packet_length, padding_length, payload, padding].pack("NCA*A*")
      mac = client.hmac.digest([client.sequence_number, unencrypted_data].pack("NA*"))

      encrypted_data = client.update_cipher(unencrypted_data) << client.final_cipher
      message = encrypted_data + mac

      debug { "queueing packet nr #{client.sequence_number} type #{payload.getbyte(0)} len #{packet_length}" }
      enqueue(message)

      client.increment(packet_length)

      self
    end

if_needs_rekey?() click to toggle source

If the IO object requires a rekey operation (as indicated by either its client or server state objects, see State#needs_rekey?), this will yield. Otherwise, this does nothing.

    # File lib/net/ssh/transport/packet_stream.rb, line 169
    def if_needs_rekey?
      if client.needs_rekey? || server.needs_rekey?
        yield
        client.reset! if client.needs_rekey?
        server.reset! if server.needs_rekey?
      end
    end

next_packet(mode=:nonblock) click to toggle source

Returns the next full packet. If the mode parameter is :nonblock (the default), then this will return immediately, whether a packet is available or not, and will return nil if there is no packet ready to be returned. If the mode parameter is :block, then this method will block until a packet is available.

    # File lib/net/ssh/transport/packet_stream.rb, line 84
    def next_packet(mode=:nonblock)
      case mode
      when :nonblock then
        if available_for_read?
          if fill <= 0
            raise Net::SSH::Disconnect, "connection closed by remote host"
          end
        end
        poll_next_packet

      when :block then
        loop do
          packet = poll_next_packet
          return packet if packet

          loop do
            result = Net::SSH::Compat.io_select([self]) or next
            break if result.first.any?
          end

          if fill <= 0
            raise Net::SSH::Disconnect, "connection closed by remote host"
          end
        end

      else
        raise ArgumentError, "expected :block or :nonblock, got #{mode.inspect}"
      end
    end

peer_ip() click to toggle source

The IP address of the peer (remote) end of the socket, as reported by the socket.

    # File lib/net/ssh/transport/packet_stream.rb, line 63
    def peer_ip
      @peer_ip ||=
        if respond_to?(:getpeername)
          addr = getpeername
          Socket.getnameinfo(addr, Socket::NI_NUMERICHOST | Socket::NI_NUMERICSERV).first
        else
          PROXY_COMMAND_HOST_IP
        end
    end

send_packet(payload) click to toggle source

Enqueues a packet to be sent, and blocks until the entire packet is sent.

    # File lib/net/ssh/transport/packet_stream.rb, line 116
    def send_packet(payload)
      enqueue_packet(payload)
      wait_for_pending_sends
    end

### Protected Instance Methods

initialize_ssh() click to toggle source

Called when this module is used to extend an object. It initializes the states and generally prepares the object for use as a packet stream.

    # File lib/net/ssh/transport/packet_stream.rb, line 181
    def initialize_ssh
      @hints  = {}
      @server = State.new(self, :server)
      @client = State.new(self, :client)
      @packet = nil
      initialize_buffered_io
    end

poll_next_packet() click to toggle source

Tries to read the next packet. If there is insufficient data to read an entire packet, this returns immediately, otherwise the packet is read, post-processed according to the cipher, hmac, and compression algorithms specified in the server state object, and returned as a new Packet object.

    # File lib/net/ssh/transport/packet_stream.rb, line 194
    def poll_next_packet
      if @packet.nil?
        minimum = server.block_size < 4 ? 4 : server.block_size
        return nil if available < minimum
        data = read_available(minimum)

        # decipher it
        @packet = Net::SSH::Buffer.new(server.update_cipher(data))
        @packet_length = @packet.read_long
      end

      need = @packet_length + 4 - server.block_size
      raise Net::SSH::Exception, "padding error, need #{need} block #{server.block_size}" if need % server.block_size != 0

      return nil if available < need + server.hmac.mac_length

      if need > 0
        # read the remainder of the packet and decrypt it.
        data = read_available(need)
        @packet.append(server.update_cipher(data))
      end

      # get the hmac from the tail of the packet (if one exists), and
      # then validate it.
      real_hmac = read_available(server.hmac.mac_length) || ""

      @packet.append(server.final_cipher)
      padding_length = @packet.read_byte

      payload = @packet.read(@packet_length - padding_length - 1)

      my_computed_hmac = server.hmac.digest([server.sequence_number, @packet.content].pack("NA*"))
      raise Net::SSH::Exception, "corrupted mac detected" if real_hmac != my_computed_hmac

      # try to decompress the payload, in case compression is active
      payload = server.decompress(payload)

      debug { "received packet nr #{server.sequence_number} type #{payload.getbyte(0)} len #{@packet_length}" }

      server.increment(@packet_length)
      @packet = nil

      return Packet.new(payload)
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.