我已经对返回外壳程序的Paramiko SSH服务器进行了概念验证。欢迎消息将打印在SSH客户端(使用macos终端SSH客户端)上,并在提示符上显示。然后客户端似乎冻结了,但是Paramiko服务器线程似乎可以正常工作。
import paramiko
from io import BytesIO
import asyncore
import socket
import threading
import logging
import sys
import cmd
LISTEN_BACKLOG = 20
class whatever:
SSH_HANDLERS = {}
SSH_BIND = ('localhost', 22)
SSH_SERVER_KEY = """\
-----BEGIN RSA PRIVATE KEY-----
<Private RSA key goes here>
-----END RSA PRIVATE KEY-----"""
settings = whatever()
class Shell(cmd.Cmd, threading.Thread):
use_rawinput = 0
intro = 'Welcome to the server!'
def __init__(self, channel):
stdin = channel.makefile('r')
stdout = channel.makefile('w')
self.__channel = channel
threading.Thread.__init__(self, name='shell')
cmd.Cmd.__init__(self, stdin=stdin, stdout=stdout)
def run(self):
self.preloop()
try:
if self.intro:
self.stdout.write(str(self.intro)+'\r\n')
stop = None
while not stop and not self.__channel.exit_status_ready():
if self.cmdqueue:
line = self.cmdqueue.pop(0)
else:
if self.use_rawinput:
try:
line = raw_input(self.prompt)
except EOFError:
line = 'EOF'
else:
self.stdout.write(self.prompt)
self.stdout.flush()
line = self.stdin.readline()
if not len(line):
line = 'EOF'
else:
line = line.rstrip('\r\n')
line = self.precmd(line)
stop = self.onecmd(line)
stop = self.postcmd(stop, line)
self.postloop()
finally:
pass
class SSHServer(paramiko.ServerInterface):
def __init__(self):
paramiko.ServerInterface.__init__(self)
self._message = None
def get_allowed_auths(self, username):
return 'publickey'
def check_auth_publickey(self, username, key):
return paramiko.AUTH_SUCCESSFUL
def check_channel_request(self, kind, chanid):
if kind == 'session':
return paramiko.OPEN_SUCCEEDED
return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
def check_channel_shell_request(self, channel):
print 'check_channel_shell_request: {:}'.format(channel)
Shell(channel).start()
return True
def check_channel_pty_request(self, channel, term, width, height, pixelwidth, pixelheight, modes):
return True
class SSHDispatcher(asyncore.dispatcher):
def __init__(self, server_key):
asyncore.dispatcher.__init__(self)
self._server_key = server_key
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(settings.SSH_BIND)
self.listen(LISTEN_BACKLOG)
def handle_accepted(self, conn, addr):
t = paramiko.Transport(conn)
t.add_server_key(self._server_key)
t.start_server(event=threading.Event(), server=SSHServer())
# python<3.2 compat
def handle_accept(self):
ret = self.accept()
if ret is not None:
self.handle_accepted(*ret)
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logging.getLogger("paramiko").setLevel(logging.DEBUG)
server_key = paramiko.RSAKey(file_obj=BytesIO(settings.SSH_SERVER_KEY))
SSHDispatcher(server_key)
asyncore.loop()
raise SystemError('SSH server loop exited')
这两个网站启发了我: https://github.com/simon-engledew/sshim/blob/master/sshim/Server.py http://nullege.com/codes/show/src@i@d@identity.gentoo.orgHEAD@okupy@common@ssh.py/100/paramiko.Transport.start_server
我想做的是通过SSH访问自定义控制台外壳程序。我实现的服务器成功生成并连接了从cmd.CMD
继承的Shell类。通过标准SSH客户端从我的终端连接到该服务器,我可以看到终端提示。
Welcome to the server!
(Cmd)
但是我无法在SSH客户端上进行交互,它已冻结。该问题与从套接字line = self.stdin.readline()
读取有关。我以前尝试使用raw_input line = raw_input(self.prompt)
进行读取,然后出现的问题是我可以在Server终端上编写命令,并在Client终端上输出命令。
如何使SSH客户端能够与服务器上的Shell交互?