使用 libssh 进行 SSH 本地端口转发

SSH local port forwarding using libssh

问题

我尝试使用 libssh with the libssh-C++-wrapper 进行本地端口转发。我的意图是通过 SSH 将服务器上的端口 localhost:3306 转发到我机器上的 localhost:3307 以通过 MySQL 连接到 localhost:3307.

void ssh_session::forward(){
    ssh::Channel channel(this->session);
    //remotehost, remoteport, localhost, localport
    channel.openForward("localhost",3306,"localhost",3307);

    std::cout<< "Channel is " << (channel.isOpen()?"open!":"closed!") << std::endl;
}

ssh::Channel 的构造函数中的 sessionssh::Session.

类型

上面的代码打印 Channel is open!。如果我尝试使用 MySQL Connector/C++ 连接到 localhost:3307,我会得到

ERROR 2003 (HY000): Can't connect to MySQL server on '127.0.0.1' (61)

观察结果

我认为这可能会导致问题。我在 ssh:Channel 中读写没问题,但 MySQL Connector/C++ 不是这样工作的。

问题

我怎样才能实现与常用 shell 命令

相同的行为
$ ssh -L 3307:localhost:3306 me@myserver.com

使用 libssh?

Warning

This function does not bind the local port and does not automatically forward the content of a socket to the channel. You still have to use channel_read and channel_write for this.

这是在告诉您,您需要编写自己的本地套接字代码。不幸的是,它不适合你。

最简单的实现是 bind 一个本地套接字,并使用 ssh_select 来侦听事件(例如到 accept 的新连接、套接字或通道事件)。您可以将套接字 fds a 和 ssh_channels 放在一个向量中以便于管理。

当你得到任何事件时,只需以非阻塞方式循环所有操作,即

  • 尝试 accept 一个新的连接,并将 fd 和一个新的 ssh_channel(按照您的问题创建)附加到您的向量中。
  • 尝试 read 所有套接字 fds,并使用 ssh_channel_write 将任何内容转发到相应的 ssh 通道(确保将 sockopt SO_RCVTIMEO 设置为 0)
  • 尝试使用 ssh_channel_read_nonblocking 读取所有频道,并使用 write 转发到套接字 fd

还需要处处处理错误,关闭相应的fd和ssh_channel。

总的来说,Whosebug 答案的代码可能太多了,但如果我有时间,我可能会回来添加它。

所有这些的诱人替代方案是 运行 ssh -L ... 作为使用 forkexec 的子进程,避免所有样板套接字代码,并从中受益来自高效、无错误的实施。