SSH local port redirection using libssh

Problem

I am trying to do local port forwarding using libssh with libssh-C ++ wrapper . My intention is to forward the port localhost:3306

to a server on localhost:3307

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;
}

      

c session

in the constructor ssh::Channel

is of type ssh::Session

.

The above code prints Channel is open!

. If I try to connect to localhost:3307

using MySQL Connector / C ++ I get

ERROR 2003 (HY000): Cannot connect to MySQL server at "127.0.0.1" (61)

Observations

  • If I use the shell command $ ssh -L 3307:localhost:3306 me@myserver.com

    everything works fine and I can connect.
  • If I use ssh::Session session

    , used in constructor or ssh::Channel channel

    to execute remote shell commands everything works, so the session is fine!
  • The libssh documentation (which is complete crap for a C ++ wrapper libsshpp.hpp

    since a lot of public member functions are not documented and you should look into the source code) shows what ssh::Channel::openForward()

    is a C wrapper functionssh_channel_open_forward()

  • documentation from ssh_channel_open_forward()

    states

    Caution
    This function does not bind a local port and does not redirect socket contents to a pipe. To do this, you still need to use channel_read and channel_write.

I think this might be causing the problem. I have no problem reading and writing to ssh:Channel

, but that's not how MySQL Connector / C ++ works.

Question

How can I achieve the same behavior produced by a common shell command

$ ssh -L 3307:localhost:3306 me@myserver.com

      

using libssh?

+3


source to share


1 answer


Warning

This function does not bind the local port and does not redirect the contents of the socket to the pipe. You still need to use channel_read and channel_write for this.

This tells you that you need to write your own local socket code. Unfortunately, it doesn't do it for you.

The simplest implementation would be a bind

local socket and use ssh_select

to listen for events (like a new event connection accept

, socket, or pipe). You can store your fd

aand socket ssh_channel

in a vector for easy handling.

When you receive any event, just iterate over all operations in a non-blocking way, i.e.



  • try a accept

    new connection and add fd and a new ssh_channel (created as in your question) to your vectors.
  • try read

    all socket fd

    s and move anything to the appropriate ssh pipe using ssh_channel_write

    (make sure setockopt SO_RCVTIMEO is 0)
  • try to read all channels using ssh_channel_read_nonblocking

    , and go to the socket fd

    with write

    .

You also need to handle errors everywhere and close the corresponding fd and ssh_channel.

All in all it will probably be too much code for a StackOverflow answer, but I can go back and add it if I get the time.

A tempting alternative to anything that would be just to run ssh -L ...

as a subprocess using fork

and exec

, avoiding all that template socket code and benefiting from an efficient, bug-free implementation.

+3


source







All Articles