近期有使用Python通过SSH连接服务器进行维护的需求,通过搜索发现使用paramiko库的居多,因此决定使用该库。经过短时间的使用后发现paramiko没有如Ruby的net/ssh一般很方便使用Socks代理的方法(可能有,出于自己初学的水平没有发现吧,从Agent相关的类发现有一些转发的痕迹,看代码依赖于具体的平台,而且还访问到环境变量,并且不确定能通过这些方法使用代理连接),希望只有寄托给其它的库,通过再次搜索发现有一些代理库,只是用起来不顺手,没有试验成功。最后在官方库发现SocksiPy,可惜这个库连最基本的“蟒蛇蛋”都没有,从http://downloads.sourceforge.net/project/socksipy/socksipy/SocksiPy%201.00/SocksiPy.zip?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fsocksipy%2Ffiles%2F&ts=1336581819&use_mirror=nchc下载源码包后发现只有一个Python源文件,README文件描述只要将该文件简单复制到site-packages即可(真希望后面能提供“蟒蛇蛋”,方便管理)。
按照文档说明复制socks.py到site-packages后开始使用,由于Socks5代理带有用户名口令认证,于是乎写如下代码进行测试:
import socks
import socket
import paramiko
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, 'socks5.proxy.com', 1080, False, 'proxy_user', 'proxy_passwd')
socket.socket = socks.socksocket
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('apps.server.com',22,username='appuser',password='apppasswd',timeout=20)
stdin,stdout,stderr = client.exec_command('ps -ef | grep root')
for std in stdout.readlines():
print std,
client.close()
执行后发现报错,内容大概是socket找不到proxy成员。通过查看socks.py的代码,最后发现应该将proxy变量改为__proxy,看来大家都不大喜欢用用户和口令验证Socks服务器,居然埋了这么个地雷,将socks.py第190行修改如下:
self.sendall("\x01" + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
接下来执行,运行成功,返回输出root用户的所有进程列表。
代理通过继承通用套接字扩展功能,只要将具有代理功能的套接字覆盖系统缺省的套接字就可以具有设置代理配置后的套接字通讯属性,做得比较巧妙!