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