jco*_*ado 15 python x11 paramiko x11-forwarding
我正在尝试运行一个命令paramiko
,应该能够打开一个X窗口.我正在使用的脚本如下:
import paramiko
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect('192.168.122.55', username='user', password='password')
transport = ssh_client.get_transport()
session = transport.open_session()
session.request_x11()
stdin = session.makefile('wb')
stdout = session.makefile('rb')
stderr = session.makefile_stderr('rb')
session.exec_command('env; xterm')
transport.accept()
print 'Exit status:', session.recv_exit_status()
print 'stdout:\n{}'.format(stdout.read())
print 'stderr:\n{}'.format(stderr.read())
session.close()
Run Code Online (Sandbox Code Playgroud)
不幸的是,当我运行上面的脚本时,我得到了这个输出:
Exit status: 1
stdout:
SHELL=/bin/bash
XDG_SESSION_COOKIE=8025e1ba5e6c47be0d2f3ad6504a25ee-1347286654.617967-1932974971
SSH_CLIENT=192.168.122.1 58654 22
USER=user
MAIL=/var/mail/user
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
PWD=/home/user
LANG=en_US.UTF-8
SHLVL=1
HOME=/home/user
LOGNAME=user
SSH_CONNECTION=192.168.122.1 58654 192.168.122.55 22
DISPLAY=localhost:10.0
_=/usr/bin/env
stderr:
xterm: Xt error: Can't open display: localhost:10.0
Run Code Online (Sandbox Code Playgroud)
如果我在终端中运行以下命令:
ssh -X user@192.168.122.55 'env; xterm'
Run Code Online (Sandbox Code Playgroud)
然后我得到相同的环境变量(虽然有些端口发生了变化),所以我说我的环境是正确的.但是,我仍然缺少一些可以paramiko
使用x11转发的东西.
我尝试过的几件事情是:
handler
参数request_x11
:除了打印值之外,我没有使用默认处理程序.auth_cookie
参数request_x11
:尝试根据xauth list
输出对正在使用的cookie值进行硬编码.这样做的想法是避免根据文档字符串paramiko
本身可能发生的问题:如果省略auth_cookie,将生成,使用和返回新的安全随机128位值.您将需要使用此值来验证传入的x11请求,并将其替换为实际的本地x11 cookie(这需要一些x11协议的知识).
还有其他一些我可以做的事情来使它工作或解决问题吗?
注意:此前已在以下位置询问过:
request_x11
我已经尝试使用的文档的唯一响应点无济于事.handler
参数,但这是错误的.Gar*_*rwe 19
阅读paramiko代码,我意识到paramiko只实现了建立x11通道的方法.它不会将通道连接到本地x11显示器.这留给你.
这是我刚写的一个小实现:
#!/usr/bin/env python
import os
import select
import sys
import paramiko
import Xlib.support.connect as xlib_connect
local_x11_display = xlib_connect.get_display(os.environ['DISPLAY'])
local_x11_socket = xlib_connect.get_socket(*local_x11_display[:3])
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect('server', username='username', password='password')
transport = ssh_client.get_transport()
session = transport.open_session()
session.request_x11(single_connection=True)
session.exec_command('xterm')
x11_chan = transport.accept()
session_fileno = session.fileno()
x11_chan_fileno = x11_chan.fileno()
local_x11_socket_fileno = local_x11_socket.fileno()
poller = select.poll()
poller.register(session_fileno, select.POLLIN)
poller.register(x11_chan_fileno, select.POLLIN)
poller.register(local_x11_socket, select.POLLIN)
while not session.exit_status_ready():
poll = poller.poll()
if not poll: # this should not happen, as we don't have a timeout.
break
for fd, event in poll:
if fd == session_fileno:
while session.recv_ready():
sys.stdout.write(session.recv(4096))
while session.recv_stderr_ready():
sys.stderr.write(session.recv_stderr(4096))
if fd == x11_chan_fileno:
local_x11_socket.sendall(x11_chan.recv(4096))
if fd == local_x11_socket_fileno:
x11_chan.send(local_x11_socket.recv(4096))
print 'Exit status:', session.recv_exit_status()
while session.recv_ready():
sys.stdout.write(session.recv(4096))
while session.recv_stderr_ready():
sys.stdout.write(session.recv_stderr(4096))
session.close()
Run Code Online (Sandbox Code Playgroud)
一些说明:
我正在使用python-Xlib的一些辅助函数.这是Xlib的纯python实现.有关安装的详细信息,请参阅此问题:如何使用pip安装Python Xlib?
我如何实现这一点的一些细节让我相信它只适用于1 x11连接(因此session.request_x11(single_connection=True)
.)我想继续努力让它处理多个连接,但那将不得不等待另一天.
此代码实际上使用以下异步方式将以下通道/套接字连接在一起select.poll
:
session.stdout
- > sys.stdout
session.stderr
- > sys.stderr
x11channel
- > local_x11_socket
local_x11_socket
- > x11channel
该paramiko
模块向模块输出许多有用的debuging信息logging
.您可以通过配置日志记录模块来查看:
import logging
logging.basicConfig(level=logging.DEBUG)
Run Code Online (Sandbox Code Playgroud)x11
请求可能使用MIT-MAGIC-COOKIE-1
您可能无法正确处理的.Xauthority
文件也可能是一个问题strace
ssh 进程并查看正常流程xterm
为strace xterm
并与上面的进行比较。一些链接:
祝你好运。
编辑:建立在加里的答案之上,具有多个 x11 连接。
#!/usr/bin/env python
import os
import select
import sys
import getpass
import paramiko
import socket
import logging
import Xlib.support.connect as xlib_connect
LOGGER = logging.getLogger(__name__)
# connection settings
host = '192.168.122.55'
user = 'user'
password = getpass.getpass()
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(host, username=user, password=password)
del password
# maintain map
# { fd: (channel, remote channel), ... }
channels = {}
poller = select.poll()
def x11_handler(channel, (src_addr, src_port)):
'''handler for incoming x11 connections
for each x11 incoming connection,
- get a connection to the local display
- maintain bidirectional map of remote x11 channel to local x11 channel
- add the descriptors to the poller
- queue the channel (use transport.accept())'''
x11_chanfd = channel.fileno()
local_x11_socket = xlib_connect.get_socket(*local_x11_display[:3])
local_x11_socket_fileno = local_x11_socket.fileno()
channels[x11_chanfd] = channel, local_x11_socket
channels[local_x11_socket_fileno] = local_x11_socket, channel
poller.register(x11_chanfd, select.POLLIN)
poller.register(local_x11_socket, select.POLLIN)
LOGGER.debug('x11 channel on: %s %s', src_addr, src_port)
transport._queue_incoming_channel(channel)
def flush_out(session):
while session.recv_ready():
sys.stdout.write(session.recv(4096))
while session.recv_stderr_ready():
sys.stderr.write(session.recv_stderr(4096))
# get local disply
local_x11_display = xlib_connect.get_display(os.environ['DISPLAY'])
# start x11 session
transport = ssh_client.get_transport()
session = transport.open_session()
session.request_x11(handler=x11_handler)
session.exec_command('xterm')
session_fileno = session.fileno()
poller.register(session_fileno, select.POLLIN)
# accept first remote x11 connection
transport.accept()
# event loop
while not session.exit_status_ready():
poll = poller.poll()
# accept subsequent x11 connections if any
if len(transport.server_accepts) > 0:
transport.accept()
if not poll: # this should not happen, as we don't have a timeout.
break
for fd, event in poll:
if fd == session_fileno:
flush_out(session)
# data either on local/remote x11 socket
if fd in channels.keys():
channel, counterpart = channels[fd]
try:
# forward data between local/remote x11 socket.
data = channel.recv(4096)
counterpart.sendall(data)
except socket.error:
channel.close()
counterpart.close()
del channels[fd]
print 'Exit status:', session.recv_exit_status()
flush_out(session)
session.close()
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5806 次 |
最近记录: |