一、总览
代理主要通过 AF_INET socket 来与远程通信,通过 AF_UNIX socket 在本地与其它进程通信。

agent.py 下的几个类主要做不同功能的代理组件,下面是个人理解,最好结合源码看。
二、类详解
1、AgentProxyThread(threading.Thread) 基类
该类是一个多线程类,初始化时接收一个 agent 类存在 _agent 变量中(paramiko 使用 AgentServerProxy 包装了这个类的实例,并将 AgentServerProxy 作为 agent 给它使用),调用 start 时会开启一个新的线程,跑到 run 逻辑。
run 逻辑流程如下:
- 通过 get_connection 拿到目标连接;
- 通过 _agent.connect 打开 agent 端的连接,并存在 agent._conn 下;
- 通过 _communicate 打开通信循环;
该类充当交互双方的中间人,代理的主要中间处理人。
1)AgentLocalProxy(AgentProxyThread)
该类的 get_connection 将会通过传入的 agent 的 get_filename 拿到文件路径,然后使用 AF_UNIX 族的 socket 创建本地进程间通信连接并返回。
该类将处理 agent 与文件之间的信息交互:

2)AgentRemoteProxy(AgentProxyThread)
该类除了传入一个 agent 外还额外传入一个 channel,get_connection 将传入的 channel 返回。
该类将处理 agent 与指定的 channel 之间的信息交互:

***修正:图中 Agent 没有对应的类的说法是错的,有一个对应的类 AgentClientProxy,这个后面讲。
2、AgentSSH(object) 基类
实现一个 _connect 方法,该方法接收一个 conn 连接,向该连接发送认证请求拿到公钥。
conn 可以是一个 paramiko 内的 channel 也可以是一个 socket 连接。
1)AgentServerProxy(AgentSSH)
需要传入一个 paramiko 的 transport 类。
这个类会创建一个文件,并将自己作为指定的 agent 通过 AgentLocalProxy 进行与文件之间的交互,流程如下:
- 在本地创建一个文件;
- 创建一个 AgentLocalProxy,将自己作为指定的 agent 并实现 get_filename 接口,调用 AgentLocalProxy 的 start 方法开启代理进程;
- connect 时通过 open_forward_agent_channel() 获得一个传入的 transport 下的 channel 作为 _conn,并对此连接跑一次 _connect;
- 通过 AgentLocalProxy 进行 agent 连接到本地文件的一个通信转发。
AgentServerProxy 代理示例
2)Agent(AgentSSH)
单纯用于获取公钥的类,该类 __init__ 的流程如下:
- 跑 AgentSSH 的 __init__;
- 主动连接到 os.environ["SSH_AUTH_SOCK"] 下的文件路径;
- 调用 _connect 请求公钥,存到 self._keys 下。
通过 get_key 可以获取该 Agent 上存储的 keys。

3、AgentClientProxy(object)
该类的 __init__ 方法接收一个 channel 对象,存在 __chanR 变量下。
该类的执行流程如下:
- 创建一个 AgentRemoteProxy,并以此作为介质将自己作为 Agent 与 __chanR 进行通信;
- 创建一个到 os.environ["SSH_AUTH_SOCK"] 路径对应文件的 socket 连接(AF_UNIX),作进程间通信;
AgentClientProxy 作代理的示例
4、AgentRequestHandler(object)
这个类用来包装一个 channel,使其向服务器发送端口转发的请求,流程如下:
- 客户端提供一个 channel,用 AgentRequestHandler(channel) 来包装这个 channel;
- AgentRequestHandler 控制 channel 调用 request_forward_agent,设定回调函数为 _forward_agent_handler;
- 服务端调用 ServerInterface 上的 check_channel_forward_agent_request 进行处理;
- 若成功则调用回调函数将指定的 channel 信道加到 handler 的列表下。

