Represents a low-level SSH session, at the transport protocol level. This handles the algorithm negotiation and key exchange for any SSH connection.
NAME | = | "Ruby/Net::SSH" |
The name that Net::SSH reports for itself | ||
PROTOCOL | = | "SSH-2.0" |
The SSH protocol supported by Net::SSH. | ||
VALID_OPTIONS | = | [ :port, :host_key, :kex, :encryption, :hmac, :compression, :languages, :compression_level, :proxy, :timeout ] |
[W] | algorithm_negotiator | |
[R] | algorithms | the collection of algorithms currently being used |
[W] | ciphers | |
[W] | compressors | |
[W] | decompressors | |
[W] | default_port | |
[W] | hmacs | |
[R] | host | the hostname that was requested |
[W] | kexs | |
[W] | logger | |
[W] | packet_receiver | |
[W] | packet_sender | |
[R] | port | the port that was requested |
[R] | session_id | the unique session identifier |
[W] | socket_factory | |
[W] | version_negotiator |
Create a new connection to the given host. This will negotiate the algorithms to use and exchange the keys. A block must be given. The uninitialized self will be passed to the block, so that dependencies may be injected.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 77 77: def initialize( host, options={} ) 78: @saved_message = nil 79: @session_id = nil 80: @host = host 81: 82: yield self 83: 84: invalid_options = options.keys - VALID_OPTIONS 85: 86: unless invalid_options.empty? 87: raise ArgumentError, 88: "invalid option(s) to #{self.class}: #{invalid_options.inspect}" 89: end 90: 91: @logger.debug "connecting" if @logger.debug? 92: 93: @port = options[ :port ] || @default_port 94: @socket = timeout( options[:timeout] || 0 ) do 95: ( options[:proxy] || @socket_factory ).open( host, @port ) 96: end 97: 98: @packet_sender.socket = @socket 99: @packet_receiver.socket = @socket 100: 101: @kex_info = { 102: :client_version_string => self.class.version, 103: :server_version_string => 104: @version_negotiator.negotiate( @socket, self.class.version ) } 105: 106: @options = options 107: kexinit 108: end
Returns the version string of this client.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 65 65: def self.version 66: "#{PROTOCOL}-#{NAME}_#{Net::SSH::Version::STRING}" 67: end
Returns the name of the client‘s host, as reported by the socket.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 120 120: def client_name 121: return @hostname if defined? @hostname 122: 123: sockaddr = @socket.getsockname 124: begin 125: @hostname = 126: Socket.getnameinfo( sockaddr, Socket::NI_NAMEREQD ).first 127: rescue 128: begin 129: @hostname = Socket.getnameinfo( sockaddr ).first 130: rescue 131: begin 132: @hostname = Socket.gethostbyname( Socket.gethostname ).first 133: rescue 134: @logger.error "the client ipaddr/name could not be determined" 135: end 136: end 137: end 138: 139: return @hostname 140: end
Closes the connection.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 155 155: def close 156: # TODO: send a DISCONNECT message to the server to close gracefully 157: @socket.close 158: end
Returns info about the remote peer
[ show source ]
# File lib/net/ssh/transport/session.rb, line 111 111: def peer 112: @peer ||= begin 113: addr = @socket.getpeername 114: ip_address = Socket.getnameinfo(addr, Socket::NI_NUMERICHOST | Socket::NI_NUMERICSERV).first 115: { :ip => ip_address, :port => @port.to_i, :host => @host } 116: end 117: end
Sends an IGNORE packet to the server, as a way to ping the connection and make sure the server knows the client is still active.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 333 333: def ping! 334: send_message [IGNORE, 4, "ping"].pack("cNA4") 335: end
Returns true if there are bytes to be read on the socket. Note that this only means there is an encrypted packet ready to be read, not that there is data available to any particular SSH channel.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 327 327: def reader_ready? 328: IO.select([@socket],nil,nil,0) != nil 329: end
Sends the given payload, using the currently configured OutgoingPacketStream.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 316 316: def send_message( message ) 317: if @logger.debug? 318: @logger.debug "sending message >>#{message.to_s.inspect}<<" 319: end 320: 321: @packet_sender.send message 322: end
Waits for the next message from the server, handling common requests like DISCONNECT, IGNORE, DEBUG, and KEXINIT in the background. The next message is returned as a [ type, buffer ] tuple, where the buffer is a Net::SSH::Util::ReaderBuffer.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 250 250: def wait_for_message 251: buffer = type = nil 252: 253: if @saved_message 254: type, buffer = @saved_message 255: @logger.debug "returning saved message: #{type}" if @logger.debug? 256: @saved_message = nil 257: else 258: loop do 259: if @logger.debug? 260: @logger.debug "waiting for packet from server..." 261: end 262: 263: buffer = @packet_receiver.get 264: next unless buffer 265: 266: type = buffer.read_byte 267: @logger.debug "got packet of type #{type}" if @logger.debug? 268: 269: case type 270: when DISCONNECT 271: reason_code = buffer.read_long 272: description = buffer.read_string 273: language = buffer.read_string 274: raise Net::SSH::Transport::Disconnect, 275: "disconnected: #{description} (#{reason_code})" 276: 277: when IGNORE 278: # do nothing 279: @logger.info "received IGNORE message " + 280: "(#{buffer.read_string.inspect})" if @logger.debug? 281: 282: when DEBUG 283: # do nothing 284: @logger.info "received DEBUG message" if @logger.debug? 285: always_display = buffer.read_bool 286: message = buffer.read_string 287: language = buffer.read_string 288: if always_display 289: @logger.warn "#{message} (#{language})" if @logger.warn? 290: else 291: @logger.debug "#{message} (#{language})" if @logger.debug? 292: end 293: 294: when KEXINIT 295: # unless we're already doing a key-exchange, do key 296: # re-exchange 297: if !@doing_kexinit 298: @logger.info "re-key requested" if @logger.info? 299: @saved_message = [ type, buffer ] 300: kexinit 301: else 302: break 303: end 304: 305: else 306: break 307: end 308: end 309: end 310: 311: return type, buffer 312: end