Blame doc/forwarding.dox

Packit Service 31306d
/**
Packit Service 31306d
@page libssh_tutor_forwarding Chapter 7: Forwarding connections (tunnel)
Packit Service 31306d
@section forwarding_connections Forwarding connections
Packit Service 31306d
Packit Service 31306d
Port forwarding comes in SSH protocol in two different flavours:
Packit Service 31306d
direct or reverse port forwarding. Direct port forwarding is also
Packit Service 31306d
named local port forwarding, and reverse port forwarding is also called
Packit Service 31306d
remote port forwarding. SSH also allows X11 tunnels.
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection forwarding_direct Direct port forwarding
Packit Service 31306d
Packit Service 31306d
Direct port forwarding is from client to server. The client opens a tunnel,
Packit Service 31306d
and forwards whatever data to the server. Then, the server connects to an
Packit Service 31306d
end point. The end point can reside on another machine or on the SSH
Packit Service 31306d
server itself.
Packit Service 31306d
Packit Service 31306d
Example of use of direct port forwarding:
Packit Service 31306d
@verbatim
Packit Service 31306d
Mail client application   Google Mail
Packit Service 31306d
         |                    ^
Packit Service 31306d
     5555 (arbitrary)         |
Packit Service 31306d
         |                143 (IMAP2)
Packit Service 31306d
         V                    |
Packit Service 31306d
    SSH client   =====>   SSH server
Packit Service 31306d
Packit Service 31306d
Legend:
Packit Service 31306d
--P-->: port connections through port P
Packit Service 31306d
=====>: SSH tunnel
Packit Service 31306d
@endverbatim
Packit Service 31306d
A mail client connects to port 5555 of a client. An encrypted tunnel is
Packit Service 31306d
established to the server. The server connects to port 143 of Google Mail (the
Packit Service 31306d
end point). Now the local mail client can retrieve mail.
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection forwarding_reverse Reverse port forwarding
Packit Service 31306d
Packit Service 31306d
The reverse forwarding is slightly different. It goes from server to client,
Packit Service 31306d
even though the client has the initiative of establishing the tunnel.
Packit Service 31306d
Once the tunnel is established, the server will listen on a port. Whenever
Packit Service 31306d
a connection to this port is made, the server forwards the data to the client.
Packit Service 31306d
Packit Service 31306d
Example of use of reverse port forwarding:
Packit Service 31306d
@verbatim
Packit Service 31306d
 Local mail server    Mail client application
Packit Service 31306d
         ^                     |
Packit Service 31306d
         |               5555 (arbitrary)
Packit Service 31306d
     143 (IMAP2)               |
Packit Service 31306d
         |                     V
Packit Service 31306d
    SSH client   <=====   SSH server
Packit Service 31306d
Packit Service 31306d
Legend:
Packit Service 31306d
--P-->: port connections through port P
Packit Service 31306d
=====>: SSH tunnel
Packit Service 31306d
@endverbatim
Packit Service 31306d
In this example, the SSH client establishes the tunnel,
Packit Service 31306d
but it is used to forward the connections established at
Packit Service 31306d
the server to the client.
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection forwarding_x11 X11 tunnels
Packit Service 31306d
Packit Service 31306d
X11 tunnels allow a remote application to display locally.
Packit Service 31306d
Packit Service 31306d
Example of use of X11 tunnels:
Packit Service 31306d
@verbatim
Packit Service 31306d
   Local display     Graphical application
Packit Service 31306d
   (X11 server)          (X11 client)
Packit Service 31306d
         ^                     |
Packit Service 31306d
         |                     V
Packit Service 31306d
    SSH client   <=====   SSH server
Packit Service 31306d
Packit Service 31306d
Legend:
Packit Service 31306d
----->: X11 connection through X11 display number
Packit Service 31306d
=====>: SSH tunnel
Packit Service 31306d
@endverbatim
Packit Service 31306d
The SSH tunnel is established by the client.
Packit Service 31306d
Packit Service 31306d
How to establish X11 tunnels with libssh has already been described in
Packit Service 31306d
this tutorial.
Packit Service 31306d
Packit Service 31306d
@see x11
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection libssh_direct Doing direct port forwarding with libssh
Packit Service 31306d
Packit Service 31306d
To do direct port forwarding, call function ssh_channel_open_forward():
Packit Service 31306d
  - you need a separate channel for the tunnel as first parameter;
Packit Service 31306d
  - second and third parameters are the remote endpoint;
Packit Service 31306d
  - fourth and fifth parameters are sent to the remote server
Packit Service 31306d
    so that they can be logged on that server.
Packit Service 31306d
Packit Service 31306d
If you don't plan to forward the data you will receive to any local port,
Packit Service 31306d
just put fake values like "localhost" and 5555 as your local host and port.
Packit Service 31306d
Packit Service 31306d
The example below shows how to open a direct channel that would be
Packit Service 31306d
used to retrieve google's home page from the remote SSH server.
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
int direct_forwarding(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
  ssh_channel forwarding_channel;
Packit Service 31306d
  int rc;
Packit Service 31306d
  char *http_get = "GET / HTTP/1.1\nHost: www.google.com\n\n";
Packit Service 31306d
  int nbytes, nwritten;
Packit Service 31306d
Packit Service 31306d
  forwarding_channel = ssh_channel_new(session);
Packit Service 31306d
  if (forwarding_channel == NULL) {
Packit Service 31306d
      return rc;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  rc = ssh_channel_open_forward(forwarding_channel,
Packit Service 31306d
                                "www.google.com", 80,
Packit Service 31306d
                                "localhost", 5555);
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
  {
Packit Service 31306d
    ssh_channel_free(forwarding_channel);
Packit Service 31306d
    return rc;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  nbytes = strlen(http_get);
Packit Service 31306d
  nwritten = ssh_channel_write(forwarding_channel,
Packit Service 31306d
                           http_get,
Packit Service 31306d
                           nbytes);
Packit Service 31306d
  if (nbytes != nwritten)
Packit Service 31306d
  {
Packit Service 31306d
    ssh_channel_free(forwarding_channel);
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  ...
Packit Service 31306d
Packit Service 31306d
  ssh_channel_free(forwarding_channel);
Packit Service 31306d
  return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
@endcode
Packit Service 31306d
Packit Service 31306d
The data sent by Google can be retrieved for example with ssh_select()
Packit Service 31306d
and ssh_channel_read(). Goggle's home page can then be displayed on the
Packit Service 31306d
local SSH client, saved into a local file, made available on a local port,
Packit Service 31306d
or whatever use you have for it.
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection libssh_reverse Doing reverse port forwarding with libssh
Packit Service 31306d
Packit Service 31306d
To do reverse port forwarding, call ssh_channel_listen_forward(),
Packit Service 31306d
then ssh_channel_accept_forward().
Packit Service 31306d
Packit Service 31306d
When you call ssh_channel_listen_forward(), you can let the remote server
Packit Service 31306d
chose the non-privileged port it should listen to. Otherwise, you can chose
Packit Service 31306d
your own privileged or non-privileged port. Beware that you should have
Packit Service 31306d
administrative privileges on the remote server to open a privileged port
Packit Service 31306d
(port number < 1024).
Packit Service 31306d
Packit Service 31306d
Below is an example of a very rough web server waiting for connections on port
Packit Service 31306d
8080 of remote SSH server. The incoming connections are passed to the
Packit Service 31306d
local libssh application, which handles them:
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
int web_server(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
  int rc;
Packit Service 31306d
  ssh_channel channel;
Packit Service 31306d
  char buffer[256];
Packit Service 31306d
  int nbytes, nwritten;
Packit Service 31306d
  int port = 0;
Packit Service 31306d
  char *helloworld = ""
Packit Service 31306d
"HTTP/1.1 200 OK\n"
Packit Service 31306d
"Content-Type: text/html\n"
Packit Service 31306d
"Content-Length: 113\n"
Packit Service 31306d
"\n"
Packit Service 31306d
"<html>\n"
Packit Service 31306d
"  <head>\n"
Packit Service 31306d
"    <title>Hello, World!</title>\n"
Packit Service 31306d
"  </head>\n"
Packit Service 31306d
"  <body>\n"
Packit Service 31306d
"    

Hello, World!

\n"
Packit Service 31306d
"  </body>\n"
Packit Service 31306d
"</html>\n";
Packit Service 31306d
Packit Service 31306d
  rc = ssh_channel_listen_forward(session, NULL, 8080, NULL);
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Error opening remote port: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return rc;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  channel = ssh_channel_accept_forward(session, 60000, &port);
Packit Service 31306d
  if (channel == NULL)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Error waiting for incoming connection: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  while (1)
Packit Service 31306d
  {
Packit Service 31306d
    nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
Packit Service 31306d
    if (nbytes < 0)
Packit Service 31306d
    {
Packit Service 31306d
      fprintf(stderr, "Error reading incoming data: %s\n",
Packit Service 31306d
              ssh_get_error(session));
Packit Service 31306d
      ssh_channel_send_eof(channel);
Packit Service 31306d
      ssh_channel_free(channel);
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    if (strncmp(buffer, "GET /", 5)) continue;
Packit Service 31306d
Packit Service 31306d
    nbytes = strlen(helloworld);
Packit Service 31306d
    nwritten = ssh_channel_write(channel, helloworld, nbytes);
Packit Service 31306d
    if (nwritten != nbytes)
Packit Service 31306d
    {
Packit Service 31306d
      fprintf(stderr, "Error sending answer: %s\n",
Packit Service 31306d
              ssh_get_error(session));
Packit Service 31306d
      ssh_channel_send_eof(channel);
Packit Service 31306d
      ssh_channel_free(channel);
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    printf("Sent answer\n");
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  ssh_channel_send_eof(channel);
Packit Service 31306d
  ssh_channel_free(channel);
Packit Service 31306d
  return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
@endcode
Packit Service 31306d
Packit Service 31306d
*/