libssh(C++)能否将指定fd的输出重定向至远程ssh_channel?
libssh通道与文件描述符交互问题解答
ssh_channel与远程侧文件描述符的对应关系
ssh_channel本身不是操作系统层面的文件描述符,它是SSH协议定义的逻辑多路复用通道,本质是建立在已加密TCP连接上的、独立的字节流拆分单元,仅用于本地libssh库和远程sshd服务端之间传输结构化的协议数据。
它和远程侧文件描述符的绑定关系是由sshd服务端动态建立的:当你通过ssh_channel_open_session打开会话后,若后续通过通道执行远程shell、启动远程可执行程序,sshd会默认把这个逻辑通道的双向流,绑定到被拉起的远程子进程的标准输入(fd 0)、标准输出(fd 1)、标准错误(fd 2)三个文件描述符上。也就是说本地通过ssh_channel_read读到的内容,本质是sshd从远程子进程fd1/fd2读出来后封装成SSH协议帧传输过来的数据,而非通道本身具备可被远程进程直接访问的fd属性。
跨主机传递本地文件描述符的可行性
跨主机通过ssh_channel传递本地已打开的文件描述符完全不具备可行性:
- 文件描述符是单操作系统内的进程资源索引,本质是本地进程文件表项的数字映射,本身不具备跨网络传输的语义和能力,这和Unix域套接字支持的同主机跨进程fd传递(SCM_RIGHTS机制)有本质区别。
- 你可以通过ssh_channel实现的,仅为把本地已打开fd中的字节内容读取出来,通过SSH协议帧传输到远程侧,由远程侧将收到的内容写入远程自己的文件或fd中——这是纯内容的拷贝传输,完全不涉及原文件描述符的访问权限、文件状态、文件锁等关联属性的传递。
远程程序fd3输出重定向到ssh_channel的实现
这种重定向完全支持,不需要修改远程现成可执行程序的代码,仅需要在远程启动程序时调整文件描述符的绑定关系即可:
- 由于sshd为会话通道默认绑定的fd1是通道的写方向,你只需要在远程执行程序的命令中,在启动程序前通过shell的重定向语法,把fd3的写入指向fd1对应的流即可,典型的启动命令格式为:
此时程序向fd3写入的所有数据,都会直接通过当前ssh_channel的写流传回本地,和普通stdout的传输路径完全一致。# 先把fd3重定向到当前通道的标准输出,再启动目标程序 exec 3>&1; /path/to/your/executable - 若需要把fd3的输出和普通stdout流做隔离,不需要修改程序逻辑,还可以利用libssh通道的扩展数据传输机制:在远程侧把fd3的输出重定向到对应扩展数据通道的写端点,libssh可以把这部分内容和标准输出、标准错误的流做拆分,本地读取时可通过扩展数据接口单独拿到fd3的输出,不会和普通stdout内容混淆。
内容的提问来源于stack exchange,提问作者leewayleaf
相关产品推荐
相关产品推荐

