1 /*
2 * vinagre-spice-tunnel.c
3 * SSH Tunneling for Vinagre
4 * This file is part of vinagre
5 *
6 * Copyright (C) 2009 - Jonh Wendell <wendell@bani.com.br>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <vinagre/vinagre-ssh.h>
24
25 #ifdef G_OS_WIN32
26 #undef DATADIR
27 #include <winsock2.h>
28 #include <ws2tcpip.h>
29 #else /* !G_OS_WIN32 */
30 #include <netinet/in.h>
31 #include <sys/socket.h>
32 #endif /* G_OS_WIN32 */
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <glib/gi18n.h>
36
37 #include "vinagre-spice-tunnel.h"
38
39 static const int TUNNEL_PORT_OFFSET = 5500;
40
41 static int
find_free_port(void)42 find_free_port (void)
43 {
44 int sock, port;
45 struct sockaddr_in6 addr;
46
47 memset (&addr, 0, sizeof (addr));
48 addr.sin6_family = AF_INET6;
49 addr.sin6_addr = in6addr_any;
50
51 sock = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
52 if (sock < 0)
53 return 0;
54
55 for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--)
56 {
57 addr.sin6_port = htons (port);
58 if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) == 0)
59 {
60 close (sock);
61 return port;
62 }
63 }
64
65 close (sock);
66 return 0;
67 }
68
69 static void
split_gateway(const gchar * gateway,gchar ** host,gint * port)70 split_gateway (const gchar *gateway, gchar **host, gint *port)
71 {
72 if (g_strrstr (gateway, ":") == NULL)
73 {
74 *host = g_strdup (gateway);
75 *port = 22;
76 }
77 else
78 {
79 gchar **server = g_strsplit (gateway, ":", 2);
80 *host = g_strdup (server[0]);
81 *port = server[1] ? atoi (server[1]) : 22;
82 g_strfreev (server);
83 }
84 }
85
86
87 gboolean
vinagre_spice_tunnel_create(GtkWindow * parent,gchar ** original_host,gchar ** original_port,gchar * gateway,GError ** error)88 vinagre_spice_tunnel_create (GtkWindow *parent,
89 gchar **original_host,
90 gchar **original_port,
91 gchar *gateway,
92 GError **error)
93 {
94 int local_port, gateway_port;
95 gchar **tunnel_str, **command_str, *gateway_host;
96
97 local_port = find_free_port ();
98 if (local_port == 0)
99 {
100 g_set_error (error,
101 VINAGRE_SPICE_TUNNEL_ERROR,
102 VINAGRE_SPICE_TUNNEL_ERROR_NO_FREE_PORT,
103 _("Unable to find a free TCP port"));
104 return FALSE;
105 }
106
107 tunnel_str = g_new (gchar *, 4);
108 tunnel_str[0] = g_strdup ("-f");
109 tunnel_str[1] = g_strdup ("-L");
110 tunnel_str[2] = g_strdup_printf ("%d:%s:%s",
111 local_port,
112 *original_host,
113 *original_port);
114 tunnel_str[3] = NULL;
115
116 command_str = g_new (gchar *, 5);
117 command_str[0] = g_strdup ("echo");
118 command_str[1] = g_strdup_printf ("%s;", VINAGRE_SSH_CHECK);
119 command_str[2] = g_strdup ("sleep");
120 command_str[3] = g_strdup ("15");
121 command_str[4] = NULL;
122
123 split_gateway (gateway, &gateway_host, &gateway_port);
124
125 if (!vinagre_ssh_connect (parent,
126 gateway_host,
127 gateway_port,
128 NULL,
129 tunnel_str,
130 command_str,
131 NULL,
132 error))
133 {
134 g_strfreev (tunnel_str);
135 g_strfreev (command_str);
136 g_free (gateway_host);
137 return FALSE;
138 }
139
140 g_strfreev (tunnel_str);
141 g_strfreev (command_str);
142 g_free (gateway_host);
143 g_free (*original_host);
144 *original_host = g_strdup ("localhost");
145 g_free (*original_port);
146 *original_port = g_strdup_printf ("%d", local_port);
147
148 return TRUE;
149 }
150
151 GQuark
vinagre_spice_tunnel_error_quark(void)152 vinagre_spice_tunnel_error_quark (void)
153 {
154 static GQuark quark = 0;
155
156 if (!quark)
157 quark = g_quark_from_string ("vinagre_spice_tunnel_error");
158
159 return quark;
160 }
161
162 /* vim: set ts=8: */
163