Send channel request from SSH server making `ssh_channel_accept_forward()` return on SSH client?
Asked Answered
D

1

10

I use the client code for direct and reverse port forwarding from the official tutorials: http://api.libssh.org/master/libssh_tutor_forwarding.html

This code works perfectly when connecting the client to an OpenSSH server on Ubuntu 16.10, i.e., direct and reverse port forwarding is achieved.

However, consider the client code for reverse port forwarding (web_server()), which makes use of the following calls:

ssh_channel_listen_forward()

ssh_channel_accept_forward()

Using my own libssh server, the problem is that the client times out in the call to ssh_channel_accept_forward() with the following error message:

"No channel request of this type from server"

That is, the error message is printed by the following client code after waiting 1 minute:

  channel = ssh_channel_accept_forward(session, 60000, &port);
  if (channel == NULL)
  {
    fprintf(stderr, "Error waiting for incoming connection: %s\n",
            ssh_get_error(session));
    return SSH_ERROR;
  }

How do I construct a channel request on the server side, such that the client doesn't time out in ssh_channel_forward_accept() and a new forward channel is created? I've tried most of the API functions without luck...

Is there a specific API function for sending such channel request? If not, how do I accomplish the task of requesting the channel?

My code on the server side goes along the following lines, where the ssh_channel_listen_forward() request is captured by the following callback function:

void global_request(ssh_session session, ssh_message message, void *userdata) {
    #ifdef DEBUG
    printf("[Debug] global_request()\n");
    #endif
    struct session_data_struct *session_data = (struct session_data_struct*) userdata;
    ssh_message_global_request_reply_success(message, 8080);
    const char *addr = ssh_message_global_request_address(message);
    int port = ssh_message_global_request_port(message);
    printf("Received global request: %s:%d\n", addr, port);
    session_data->channel = ssh_channel_new(session);
    ssh_channel ch = ssh_message_channel_request_channel(message);
    if (ssh_channel_is_open(session_data->channel)) {
        printf("Channel is open!\n");
    }
}

However, as stated, the server is not making the client accept a new forward channel in the call to ssh_channel_accept_forward().

Any ideas?

Duvall answered 4/8, 2017 at 9:22 Comment(1)
+ 1 for asking a SSH question that's actually about programming or developmentBalk
L
1

Your server code don't send request to open reverse tunnel to client side. This channel: session_data->channel created not bound at server side. You can try to connect it, but in this case you should set subtype "forwarded-tcpip" manually.

This request: ssh_message_channel_request_channel(message); returns NULL because port forwarding request has no channel field.

For initiation of reverse tunnel, that you can accept with ssh_channel_accept_forward() - you should connect to the bound listening port at the server side. (port number from ssh_channel_listen_forward() you know).

P.S. And don't use server callbacks to accept this request. Libssh still filter this message subtype from callback processing.

P.P.S. Read RFC (https://www.rfc-editor.org/rfc/rfc4254#page-7) and library source. It's completely readable and not that big

Lallation answered 4/8, 2017 at 12:17 Comment(22)
I'm still a little unsure about what to do. Could you give an example of initiating a reverse tunnel?Duvall
For test you can simply connect to forwarded port with telnet. Or create a socket at server side and connect it to forwarded port at localhost.Lallation
Could you describe more simply what the server side should do after receiving the forward-listen message? I'm new, so I need small steps. Thanks for your answer btw.Duvall
For setting a subtype manually you have to use internal library functions like rc = channel_open(channel, "direct-tcpip", CHANNEL_INITIAL_WINDOW, CHANNEL_MAX_PACKET, payload); but it's not recommended without complete understanding what are you doing.Lallation
After receiving forward listen message server should reply with byte SSH_MSG_REQUEST_SUCCESS uint32 port that was bound on the server And wait for incoming connections on bound port. When connection occurs it should request new channel with type: byte SSH_MSG_CHANNEL_OPEN string "forwarded-tcpip" And pipe data from bound port to this channel and back.Lallation
I will try that! This comment makes much more sense to me. Thank you!Duvall
Are you saying that the server callback mechanism is buggy?Duvall
How would I use the internal open_channel function? If it is internal it is not included as part of the API? Shouldn't the API allow for forward connections? Otherwise the API is incomplete/insufficient?Duvall
Are you saying that the server callback mechanism is buggy? It's not buggy it's just not supposed to process tunnels ` case SSH_REQUEST_CHANNEL_OPEN: if (msg->channel_request_open.type == SSH_CHANNEL_SESSION && ssh_callbacks_exists(session->server_callbacks, channel_open_request_session_function))` This if in messages.c - filter types of channel open requestsLallation
How would I use the internal open_channel function? Just for clear understanding - what do you suppose to do via tunnel? Probably you need simple direct forward tunnel, but try to use reverse one.Lallation
I've recently started to read about the features of SSH and one of them is reverse port forwarding. Actually, I don't need it for much right now. I just want to learn how to do it. Having looked through the source code of libssh once again, how do I use the open_channel function when it is internal? I don't understand why there are no functions in libssh.h or server.h that I can use for requesting the channel? Thanks for your advice.Duvall
Could you add some code to you answer for completeness :-)?Duvall
In the plain C we can't make private declarations. So formally you can use any function in library, but maintainers also feel free to change non-documented in API code without any notifications. Code for reverse tunnel in library tutorial works well, you just need standalone application to make http GET-request on tunneled portLallation
But, the internal functions are not exposed from the libssh.so library? Only library functions are declared with LIBSSH_API?Duvall
Yes, sorry, I miss static in definition. You could not use this func without lib edit.Lallation
so what you are saying is that I need to modify the source and recompile/install? I think it is weird that libssh provide no support for reverse forwarding by default.Duvall
It supports. You have to use it correctly. Reverse forward tunnel will create channel automatically after you make connection to forwarded port. You shouldn't do it manuallyLallation
It isn't working for me :-( - Have you tried it? If so, would you add snippets of your code to your answer?Duvall
Kind of a metacode - session initialization (set options, connect, authorization) - set remote forward (ssh_channel_listen_forward) while(!channel = ssh_channel_accept_forward(session, 0, &tunneledPort)) { sleep(SLEEPTIME); } while(true) ssh_select(socket, channel) data piping between socket and channel if (eof from either side) { flush remaining data break; } } clearing (disconnect channel, session, socket) Like thisLallation
This I do. What I need is a way for the client to open the channel. The server waits in ssh_channel_accept_forward(), since the client never sends the channel request.Duvall
Lets define what is cllient and what is server in your app. You have client it initialize session to server, right? Than client set remote forward in session, so it opens forwarded port on server side Than client should wait to accept forward. When connection to forwarded port on server side occurs - server initiate an channel request back to client, who accept_forward it and communicate. It's reverse forwarding.Lallation
I guess this is what I do. Would you look at my code to see where things go wrong? If so, how can I share it with you?Duvall

© 2022 - 2024 — McMap. All rights reserved.