Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/net/ssh/command_stream.rb
Views: 11779
# -*- coding: binary -*-12class Net::SSH::CommandStream34attr_accessor :channel, :thread, :error, :ssh5attr_accessor :lsock, :rsock, :monitor67module PeerInfo8include ::Rex::IO::Stream9attr_accessor :peerinfo10attr_accessor :localinfo11end1213def shell_requested(channel, success)14unless success15raise Net::SSH::ChannelRequestFailed, 'Shell/exec channel request failed'16end1718self.channel = channel1920channel[:data] = ''21channel[:extended_data] = ''2223channel.on_eof do24cleanup25end2627channel.on_close do28cleanup29end3031channel.on_data do |ch, data|32self.rsock.write(data)33channel[:data] << data34end3536channel.on_extended_data do |ch, ctype, data|37self.rsock.write(data)38channel[:extended_data] << data39end40end4142def initialize(ssh, cmd = nil, pty: false, cleanup: false)43self.lsock, self.rsock = Rex::Socket.tcp_socket_pair()44self.lsock.extend(Rex::IO::Stream)45self.lsock.extend(PeerInfo)46self.rsock.extend(Rex::IO::Stream)4748self.ssh = ssh49self.thread = Thread.new(ssh, cmd, pty, cleanup) do |rssh, rcmd, rpty, rcleanup|50info = rssh.transport.socket.getpeername_as_array51if Rex::Socket.is_ipv6?(info[1])52self.lsock.peerinfo = "[#{info[1]}]:#{info[2]}"53else54self.lsock.peerinfo = "#{info[1]}:#{info[2]}"55end5657info = rssh.transport.socket.getsockname58if Rex::Socket.is_ipv6?(info[1])59self.lsock.localinfo = "[#{info[1]}]:#{info[2]}"60else61self.lsock.localinfo = "#{info[1]}:#{info[2]}"62end6364channel = rssh.open_channel do |rch|65# A PTY will write us to {u,w}tmp and lastlog66rch.request_pty if rpty6768if rcmd.nil?69rch.send_channel_request('shell', &method(:shell_requested))70else71rch.exec(rcmd, &method(:shell_requested))72end73end7475channel.on_open_failed do |ch, code, desc|76raise Net::SSH::ChannelOpenFailed.new(code, 'Session channel open failed')77end7879self.monitor = Thread.new do80while(true)81next if not self.rsock.has_read_data?(1.0)82buff = self.rsock.read(16384)83break if not buff84verify_channel85self.channel.send_data(buff) if buff86end87end8889while true90rssh.process(0.5) { true }91end9293# Shut down the SSH session if requested94if !rcmd.nil? && rcleanup95rssh.close96end97end98rescue ::Exception => e99# XXX: This won't be set UNTIL there's a failure from a thread100self.error = e101ensure102self.monitor.kill if self.monitor103end104105#106# Prevent a race condition107#108def verify_channel109while ! self.channel110raise EOFError if ! self.thread.alive?111::IO.select(nil, nil, nil, 0.10)112end113end114115def cleanup116self.monitor.kill117self.lsock.close rescue nil118self.rsock.close rescue nil119self.ssh.close rescue nil120self.thread.kill121end122123end124125126