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 | |
[W] | kexs | |
[W] | logger | |
[W] | packet_receiver | |
[W] | packet_sender | |
[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 71 71: def initialize( host, options={} ) 72: @saved_message = nil 73: @session_id = nil 74: @host = host 75: 76: yield self 77: 78: invalid_options = options.keys - VALID_OPTIONS 79: 80: unless invalid_options.empty? 81: raise ArgumentError, 82: "invalid option(s) to #{self.class}: #{invalid_options.inspect}" 83: end 84: 85: @logger.debug "connecting" if @logger.debug? 86: 87: @port = options[ :port ] || @default_port 88: @socket = timeout( options[:timeout] || 0 ) do 89: ( options[:proxy] || @socket_factory ).open( host, @port ) 90: end 91: 92: @packet_sender.socket = @socket 93: @packet_receiver.socket = @socket 94: 95: @kex_info = { 96: :client_version_string => self.class.version, 97: :server_version_string => 98: @version_negotiator.negotiate( @socket, self.class.version ) } 99: 100: @options = options 101: kexinit 102: end
Returns the version string of this client.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 59 59: def self.version 60: "#{PROTOCOL}-#{NAME}_#{Net::SSH::Version::STRING}" 61: end
Returns the name of the client‘s host, as reported by the socket.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 114 114: def client_name 115: return @hostname if defined? @hostname 116: 117: sockaddr = @socket.getsockname 118: begin 119: @hostname = 120: Socket.getnameinfo( sockaddr, Socket::NI_NAMEREQD ).first 121: rescue 122: begin 123: @hostname = Socket.getnameinfo( sockaddr ).first 124: rescue 125: begin 126: @hostname = Socket.gethostbyname( Socket.gethostname ).first 127: rescue 128: @logger.error "the client ipaddr/name could not be determined" 129: end 130: end 131: end 132: 133: return @hostname 134: end
Closes the connection.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 149 149: def close 150: # TODO: send a DISCONNECT message to the server to close gracefully 151: @socket.close 152: end
Returns info about the remote peer
[ show source ]
# File lib/net/ssh/transport/session.rb, line 105 105: def peer 106: @peer ||= begin 107: addr = @socket.getpeername 108: ip_address = Socket.getnameinfo(addr, Socket::NI_NUMERICHOST | Socket::NI_NUMERICSERV).first 109: { :ip => ip_address, :port => @port.to_i, :host => @host } 110: end 111: 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 327 327: def ping! 328: send_message [IGNORE, 4, "ping"].pack("cNA4") 329: 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 321 321: def reader_ready? 322: IO.select([@socket],nil,nil,0) != nil 323: end
Sends the given payload, using the currently configured OutgoingPacketStream.
[ show source ]
# File lib/net/ssh/transport/session.rb, line 310 310: def send_message( message ) 311: if @logger.debug? 312: @logger.debug "sending message >>#{message.to_s.inspect}<<" 313: end 314: 315: @packet_sender.send message 316: 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 244 244: def wait_for_message 245: buffer = type = nil 246: 247: if @saved_message 248: type, buffer = @saved_message 249: @logger.debug "returning saved message: #{type}" if @logger.debug? 250: @saved_message = nil 251: else 252: loop do 253: if @logger.debug? 254: @logger.debug "waiting for packet from server..." 255: end 256: 257: buffer = @packet_receiver.get 258: next unless buffer 259: 260: type = buffer.read_byte 261: @logger.debug "got packet of type #{type}" if @logger.debug? 262: 263: case type 264: when DISCONNECT 265: reason_code = buffer.read_long 266: description = buffer.read_string 267: language = buffer.read_string 268: raise Net::SSH::Transport::Disconnect, 269: "disconnected: #{description} (#{reason_code})" 270: 271: when IGNORE 272: # do nothing 273: @logger.info "received IGNORE message " + 274: "(#{buffer.read_string.inspect})" if @logger.debug? 275: 276: when DEBUG 277: # do nothing 278: @logger.info "received DEBUG message" if @logger.debug? 279: always_display = buffer.read_bool 280: message = buffer.read_string 281: language = buffer.read_string 282: if always_display 283: @logger.warn "#{message} (#{language})" if @logger.warn? 284: else 285: @logger.debug "#{message} (#{language})" if @logger.debug? 286: end 287: 288: when KEXINIT 289: # unless we're already doing a key-exchange, do key 290: # re-exchange 291: if !@doing_kexinit 292: @logger.info "re-key requested" if @logger.info? 293: @saved_message = [ type, buffer ] 294: kexinit 295: else 296: break 297: end 298: 299: else 300: break 301: end 302: end 303: end 304: 305: return type, buffer 306: end