def close_session(self, channel: paramiko.Channel) -> None: # pylint: disable=protected-access if channel.closed: return if not channel.eof_received: message = Message() message.add_byte(cMSG_CHANNEL_EOF) message.add_int(channel.remote_chanid) channel.transport._send_user_message(message) # type: ignore message = Message() message.add_byte(cMSG_CHANNEL_REQUEST) message.add_int(channel.remote_chanid) message.add_string('*****@*****.**') message.add_boolean(False) channel.transport._send_user_message(message) # type: ignore message = Message() message.add_byte(cMSG_CHANNEL_CLOSE) message.add_int(channel.remote_chanid) channel.transport._send_user_message(message) # type: ignore channel._unlink() # type: ignore super(SCPBaseForwarder, self).close_session(channel) logging.debug("[chan %d] SCP closed", channel.get_id())
def shell(channel: paramiko.Channel): stdin: paramiko.ChannelFile = channel.makefile_stdin("wb") stdout: paramiko.ChannelFile = channel.makefile("r") stderr: paramiko.ChannelFile = channel.makefile_stderr("r") print("Tip: F12 + I to show connection info, F12+C to close connection") stdoutReader = Thread(target=__buffered_reader, name="stdoutReader", args=(stdout, sys.stdout)) stderrReader = Thread(target=__buffered_reader, name="stderrReader", args=(stderr, sys.stderr)) stdinWriter = Thread(target=__input_handler, name="stdinWriter", args=(sys.stdin, stdin, channel)) sizeHandler = Thread(target=__window_size_change_handler, name="TerminalSizeWatchdog", args=(channel,)) sizeHandler.setDaemon(True) stdoutReader.setDaemon(True) stderrReader.setDaemon(True) stdinWriter.setDaemon(True) orig_sigint = signal.getsignal(signal.SIGINT) try: signal.signal(signal.SIGINT, _sigint) sizeHandler.start() stderrReader.start() stdoutReader.start() stdinWriter.start() stdoutReader.join() finally: print("Closing ssh session...") try: channel.close() except: pass signal.signal(signal.SIGINT, orig_sigint)
def close_session(self, channel: paramiko.Channel) -> None: channel.lock.acquire() if not channel.closed: channel.lock.release() channel.close() if channel.lock.locked(): channel.lock.release()
def __window_size_change_handler(channel: paramiko.Channel): width, height = get_terminal_size() while not SIGINT: time.sleep(1) nwidth, nheight = get_terminal_size() if nwidth != width or nheight != height: width, height = nwidth, nheight channel.resize_pty(width=width, height=height)
def read_out(chan: paramiko.Channel, wait_time=1) -> str: now = time.time() out = '' while True: while chan.recv_ready(): data = chan.recv(256).decode('utf-8') out = out + data sys.stdout.write(data) # and time.time() - now > 3 while not chan.recv_ready() and time.time() - now > wait_time: return out
def send_tree(self, chan: paramiko.Channel, path: str) -> typing.Tuple[list, list]: """ Request a "send tree" request to the client given a channel and path :param chan: Channel to send the request for :param file_path: Path of the request :return: Dirs and files in the tree """ chan.send(self.SEND_TREE) logging.debug("TREE:tree request sent") size = len(path) size = str(size) size += '.' * int((64 - len(size))) chan.send(str(size)) logging.debug("TREE:tree size sent") chan.send(path) logging.debug("TREE:tree path sent") logging.debug("TREE:waiting for size") size = chan.recv(64) logging.debug("TREE:got size") size = size.decode('utf-8') size = size.replace('.', '') logging.debug("TREE:wating for tree") raw_tree = chan.recv(int(size)) logging.debug("TREE:got tree") dirs, files = pickle.loads(raw_tree) return dirs, files
def _f12_commands(channel: paramiko.Channel): global F12MENU global SIGINT _k = _getch() if _k == FUNC_KEYS.F12.value: F12MENU = not F12MENU print(f"\n Character code debugging is: {F12MENU}") if F12MENU: print("> ", end='', flush=True) elif _k == (99,): # C: SIGINT = True elif _k == (105,): # I t: paramiko.Transport = channel.get_transport() sock: socket = t.sock localname, peername = sock.getsockname(), sock.getpeername() local = localname if localname else ("unknown", 0) remote = peername if peername else ("unknown", 0) print(f""" Connection: {t.local_version} -> {t.remote_version} ({'active' if t.active == 1 else 'inactive'}, auth: {t.authenticated}) Local endpoint: {local[0]}:{local[1]}, host key type = {t.host_key_type} Repote Endpoint: {remote[0]}:{remote[1]}, chipher type = {t.remote_cipher}, mac = {t.remote_mac} Preffered: Ciphers: {','.join(t.preferred_ciphers)} Keys: {','.join(t.preferred_keys)} Macs: {','.join(t.preferred_macs)} """) else: return chr(7)
def do_makefile(*args): if ch.channel_file is None: ch.channel_file = Channel.makefile(ch, *args) _override_file_close(ch.channel_file) return ch.channel_file else: raise FileExistsError('We allow only one file per channel')
def handler(self, channel: paramiko.Channel, origin: Optional[Tuple[str, int]], destination: Optional[Tuple[str, int]]) -> None: try: logging.debug( "Opening forwarded-tcpip channel (%s -> %s) to client", origin, destination) f = TunnelForwarder( self.session.transport.open_channel("forwarded-tcpip", destination, origin), channel) self.server_interface.forwarders.append(f) except paramiko.ssh_exception.ChannelException: channel.close() logging.error("Could not setup forward from %s to %s.", origin, destination)
def _override_channel_close(ch: Channel): ch.channel_file = None ch.close_pending = False def do_close(): if ch.channel_file is not None and not ch.channel_file.closed: ch.close_pending = True return else: try: return Channel.close(ch) except EOFError as e: # Some problems while closing yield an EOFError, which is not # descriptive raise ConnectionError('Closing channel') from e ch.close = do_close
def select_group_or_not(chan: paramiko.Channel, config: dict): out_info = read_out(chan, wait_time=3) if "elect group" not in out_info: return idx = '0' group_list = out_info.split("\r\n") for ip_addr in group_list: if config.get("select_ip") in ip_addr: idx = ip_addr[1:ip_addr.index(":")].strip() print("select " + idx) break if idx == '0': print("ip 未找到") return False chan.send(idx + '\n') read_out(chan, wait_time=3) return True
def right_forwarder(channel: Channel, local_port: int): selector = selectors.DefaultSelector() def from_localhost(): data = sock.recv(1024) if len(data) == 0: return data channel.send(data) return data def to_localhost(): data = sock.recv(1024) if len(data) == 0: return data channel.send(data) return data selector.register(socket, selectors.EVENT_READ, from_localhost) selector.register(channel, selectors.EVENT_READ, to_localhost) # connect to localhost via sockets sock = socket.socket() try: sock.connect((LOCALHOST, local_port)) except Exception as e: logger.error(f'Forwarding request to {local_port} failed: e') return # read data from channel or socket and send to opposite site while True: r, _, _ = select.select([sock, channel], [], []) if sock in r: data = sock.recv(1024) if len(data) == 0: break channel.send(data) if channel in r: data = channel.recv(1024) if len(data) == 0: break sock.send(data) channel.close() sock.close() logger.info(f'Tunnel closed from {channel.origin_addr}')
def _override_makefile(ch: Channel): # makefile for channels should work the same way as for sockets, but that's # not the case. In particular, if you close the channel the file remains # unusable, which is bad. # When doing makefile on a channel, we store a pointer to the file, so that # when trying to close the channel we can check if the file is still open # and leave the closure pending. We override the close method in the file # as to execute the pending closure if needed. ch.channel_file = None def do_makefile(*args): if ch.channel_file is None: ch.channel_file = Channel.makefile(ch, *args) _override_file_close(ch.channel_file) return ch.channel_file else: raise FileExistsError('We allow only one file per channel') ch.makefile = do_makefile
def __get_data_from_channel(self, channel: paramiko.Channel, stream_name: str, timeout: float) -> Tuple[bool, str]: """Reads text from standard output or standard error.""" if stream_name == 'stdout': receive = paramiko.Channel.recv else: receive = paramiko.Channel.recv_stderr channel.settimeout(timeout) data = bytearray() try: new_data = receive(channel, 1024 * 1024) while len(new_data) > 0: data.extend(new_data) new_data = receive(channel, 1024 * 1024) except socket.timeout: return False, data.decode('utf-8') return True, data.decode('utf-8')
def _handle_client(self, channel: paramiko.Channel) -> None: try: command = self.command_queues[channel.chanid].get(block=True) _logger.debug(f"Channel {channel.chanid}, executing {command}") command_result = self._command_handler(command.decode()) channel.sendall(command_result.stdout) channel.sendall_stderr(command_result.stderr) channel.send_exit_status(command_result.returncode) except Exception: # pylint: disable=broad-except _logger.exception(f"Error handling client (channel: {channel})") finally: try: channel.close() except EOFError: _logger.debug("Tried to close already closed channel")
def sendall(self, channel: paramiko.Channel, data: bytes, sendfunc: Callable[[bytes], int]) -> int: if not data: return 0 if channel.exit_status_ready(): return 0 sent = 0 newsent = 0 while sent != len(data): newsent = sendfunc(data[sent:]) if newsent == 0: return 0 sent += newsent return sent
def _initiate_channel(self, channel: paramiko.Channel, email: str): """ Initiates channel with given channel object and email :param channel: SSH Channel object :param email: user's email """ data = channel.recv(5) data = data.decode("utf-8") logging.debug("Data recived: {data}".format(data=data)) if data == self.READY: size = channel.recv(64) size = size.decode('utf-8') size = size.replace('.', '') name = channel.recv(int(size)) setattr(channel,"anylink_name",name.decode('utf-8')) channel.send(self.CONFIRM_READY) self.channels[channel] = email else: channel.close()
def send_file(self, chan: paramiko.Channel, file_path: str) -> bool: """ Request a "send file" request to the client given a channel and file path :param chan: Channel to send the request for :param file_path: Path of the file of the request :return: File transfer succeeded/faild - True/False """ chan.send(self.SEND_FILE) size = str(len(file_path)) size += '.' * int((64 - len(size))) chan.send(str(size)) chan.send(file_path) size = chan.recv(64) size = size.decode('utf-8') size = size.replace('.', '') msg = chan.recv(int(size)) msg = msg.decode('utf-8') logging.debug("Message recived: {msg}".format(msg=msg)) if msg == "finishfile": return True return False
def make_interactive( channel: paramiko.Channel ) -> typing.Tuple[int, typing.BinaryIO, typing.BinaryIO]: """ Manages an interactive command Takes in a paramiko.Channel shared by stdin, stdout, stderr of a currently running command The current interpreter stdin is duplicated and written to the command's stdin The command's stdout and stderr are written to the interpreter's stdout and stderr and also buffered in a ByteStream for later reading Returns (exit status, Stdout buffer, Stderr bufer) """ infd = sys.stdin.fileno() channelfd = channel.fileno() poll = select.poll() poll.register( infd, select.POLLIN + select.POLLPRI + select.POLLERR + select.POLLHUP) poll.register( channelfd, select.POLLIN + select.POLLPRI + select.POLLERR + select.POLLHUP) stdout = io.BytesIO() stderr = io.BytesIO() while not channel.exit_status_ready(): for fd, event in poll.poll(0.5): if fd == infd and event & (select.POLLIN + select.POLLPRI): # Text available on python stdin channel.send(os.read(infd, 4096)) if channel.recv_ready(): content = channel.recv(4096) sys.stdout.write(content.decode()) sys.stdout.flush() stdout.write(content) if channel.recv_stderr_ready(): content = channel.recv_stderr(4096) sys.stderr.write(content.decode()) sys.stderr.flush() stderr.write(content) if channel.recv_ready(): content = channel.recv(4096) sys.stdout.write(content.decode()) sys.stdout.flush() stdout.write(content) if channel.recv_stderr_ready(): content = channel.recv_stderr(4096) sys.stderr.write(content.decode()) sys.stderr.flush() stderr.write(content) stdout.seek(0, 0) stderr.seek(0, 0) return channel.recv_exit_status(), stdout, stderr
def exec_command(chan: paramiko.Channel, commands: list): for cmd in commands: chan.send(cmd + '\n') read_out(chan, wait_time=2)
def __init__(self, chan: Channel): self.chan = chan # need that U. no universal new line = pressing enter might not stop sending data.. self.chanfile = chan.makefile('rU')
def check_channel_exec_request(self, channel: paramiko.Channel, command: bytes) -> bool: self.command_queues.setdefault(channel.get_id(), Queue()).put(command) return True
def test_can_override_mode_and_bufsize(self, setmode): self.klass(Channel(None), mode="w", bufsize=25) setmode.assert_called_once_with("w", 25)
def test_defaults_to_unbuffered_reading(self, setmode): self.klass(Channel(None)) setmode.assert_called_once_with("r", -1)
def close_channel(self, channel: Channel): channel.close()
def wait_until_end(self, channel: Channel): status = channel.recv_exit_status() return status