Blame doc/forwarding.dox

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

Hello, World!

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