|
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 |
*/
|