简短版:
paramiko.Packetizer.need_rekey()
,然后在我的数据传输线程中阻塞或睡眠(如果它返回True)我的问题:
paramiko.Packetizer.need_rekey()
对象时,如何访问paramiko.SSHClient()
的任何参考或示例 长版:
现代SSH会话需要在经过一定时间或数据后重新生成密钥。如果对重新加密的请求没有足够快地采取行动 - 那么"足够快"自请求重定密钥以来意味着太多时间或太多数据已经过去 - 连接被中止为安全保护机制。
Paramiko曾经在重定密钥请求和重新加密之间有非常窄的20个数据包限制。 2012年This patch
增加(d)重新密钥请求和&之间接收的数据包的限制。 完成从20包到2 ** 29包。
在我的应用程序中,我使用paramiko.transport.open_channel
通过转发端口传输大型(10-30 GB)数据流。如果我在同一局域网上的两台主机之间执行此操作,则它会100%成功完成。如果主机位于不同的局域网上,延迟越来越高,它就开始出现故障 - 让我们说50%的时间,但可能会超过这个。
毋庸置疑,将30 GB的SSH连接丢失到30 GB的数据传输可能会令人沮丧。
使用OpenSSH作为客户端,我没有这个问题,这与我已经读过的报告一致,即重新加密互操作性是有问题的。据报道,OpenSSH与本身无缝地重新密钥;与其他人 ......不那么重要。但我已经使用Paramiko登录远程主机并运行必要的命令来启动数据传输;不得不打开一个单独的OpenSSH会话只是为了转发数据的端口是混乱的。
正确的解决方案似乎是Paramiko应该阻止或延迟非重新密钥数据包,同时它会重新打开 - 这似乎是OpenSSH处理它的方式,尽管我还没有看到权威的确认那。但这可能是一个雄心勃勃的变化,会影响很多人并花时间。
作为一项临时措施,简单的解决办法是让我的脚本自我调节。我很乐意在重新加密处理时插入sleep
个电话或完全阻止数据传输。如果没有在后台进行大规模数据传输,重新加密应该很容易在截止日期内完成。
Paramiko提供了一种查看是否已请求重定密钥的方法 - paramiko.Packetizer.need_rekey()
。但我不知道如何在我现有的SSHClient()
对象的上下文中调用它。对于paramiko.transport.*
方法,我可以使用paramiko.SSHClient().get_transport()
来创建用于调用它们的对象。对于获取对Packetizer方法的访问权限,似乎没有paramiko.SSHClient().get_packetizer()
等效项。 demo/
代码中没有Packetizer的示例,test_packetizer.py
下的tests/
文件表明它被设计为用作原始界面,而不是{{1} }。
所以 - 重申上面简短版本的问题 -
SSHClient
为True时,我认为我可以通过sleep()
解决此问题,但我不知道如何从我的上下文中访问paramiko.Packetizer.need_rekey()
方法拥有need_rekey()
个对象。有什么想法吗?感谢任何帮助!
版本信息FYI:
SSHClient
答案 0 :(得分:1)
我仍然希望听到#2的好答案......
我通过黑客攻击和削减找到了#1的答案:transport
返回的get_transport
对象包含一个packetizer
对象,可用于解决need_rekey()
方法:
$ python
Python 2.7.5 (default, Apr 9 2015, 11:03:32)
[GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import paramiko
>>> ssh = paramiko.SSHClient()
>>> omkey = paramiko.RSAKey.from_private_key_file('./privkey.rsa')
>>> ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
>>> ssh.connect('gowenfawr.example.com', username='gowenfawr', pkey=omkey)
>>> transport = ssh.get_transport()
>>> transport.packetizer
<paramiko.packet.Packetizer object at 0x7fb121aa5650>
>>> transport.packetizer.need_rekey()
False
>>>
我更新了我的&#34;数据读取&#34;循环以检查是否设置了transport.packetizer.need_rekey()
,如果是,则使用time.sleep(1)
进行休眠。以下代码打印出来&#39;。&#39;每1/80数据传输进度和一个&#39; Z&#39;因为已经请求了重新密钥,它会在暂停时打印出来:
track = 0
hash = int(size/80)
while True:
r, w, x = select.select([chan], [], [])
if chan in r:
data = chan.recv(1024)
if len(data) == 0:
break
os.write(fp[0], data)
track = track + len(data)
if transport.packetizer.need_rekey():
sys.stdout.write('Z')
sys.stdout.flush()
time.sleep(1)
if track > hash:
sys.stdout.write('.')
sys.stdout.flush()
track = 0
print ''
这导致了这种输出
$ grabdata.py gowenfawr.example.com
target is gowenfawr.example.com
Found appropriate kernel version
Setting up data transfer
.....Z.....Z.....Z.....Z......Z.....Z.....Z.....Z.....Z......Z.....Z.....Z.....Z.....Z......Z.....Z...
Transfer complete!
$
这告诉我,重复密钥正在定期发生(好的,考虑到这里传输的数据量很大),自从更改以来,我无法重现超过10次运行的会话中止失败。