Problem
I try to do local port forwarding using libssh with the libssh-C++-wrapper. My intention is to forward port localhost:3306
on a server to localhost:3307
on my machine via SSH to connect via MySQL to 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;
}
with session
in the constructor of ssh::Channel
being of type ssh::Session
.
The code above prints Channel is open!
. If I try to connect to localhost:3307
using the MySQL Connector/C++ I get
ERROR 2003 (HY000): Can't connect to MySQL server on '127.0.0.1' (61)
Observations
$ ssh -L 3307:localhost:3306 [email protected]
everything works fine and I can connect.ssh::Session session
used in the constructor or ssh::Channel channel
to execute remote shell commands everything works therefore the session is fine!libsshpp.hpp
since a lot of public member functions are not documented and you have to look into the source code) shows that ssh::Channel::openForward()
is a wrapper for the C function ssh_channel_open_forward()
ssh_channel_open_forward()
states
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.
I think that could cause the problem. I have no problem by reading and writing in to the ssh:Channel
but thats not how the MySQL Connector/C++ works.
Question
How can I achieve the same behaviour produced by the common shell command
$ ssh -L 3307:localhost:3306 [email protected]
using 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.
This is telling you that you need to write your own local socket code. Unfortunately, it doesn't do it for you.
The simplest implementation would be to bind
a local socket, and use ssh_select
to listen for events (e.g. new connection to accept
, socket or channel events). You can keep your socket fd
s aand ssh_channel
s in a vector for easy management.
When you get any event, just loop over all the operations in a non-blocking way, i.e.
accept
a new connection, and append the fd, and a new ssh_channel (created as in your question) to your vectors.read
all the socket fd
s, and forward anything to the corresponding ssh channel using ssh_channel_write
(make sure to setsockopt SO_RCVTIMEO to 0)ssh_channel_read_nonblocking
, and forward to the socket fd
using write
.You also need to handle errors everywhere, and close the corresponding fd and ssh_channel.
Overall it's probably going to be too much code for a StackOverflow answer, but I may come back and add it in if I get time.
The tempting alternative to all that would be to just run ssh -L ...
as a subprocess using fork
& exec
, avoiding all that boilerplate socket code, and benefitting from an efficient, bug-free implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With