Branch data Line data Source code
1 : : #include <gio/gio.h>
2 : : #include <gio/gunixsocketaddress.h>
3 : : #include <glib.h>
4 : : #include <stdlib.h>
5 : : #include <stdio.h>
6 : : #include <string.h>
7 : :
8 : : #include "gtlsconsoleinteraction.h"
9 : :
10 : : GMainLoop *loop;
11 : :
12 : : gboolean verbose = FALSE;
13 : : gboolean non_blocking = FALSE;
14 : : gboolean use_udp = FALSE;
15 : : int cancel_timeout = 0;
16 : : int read_timeout = 0;
17 : : gboolean unix_socket = FALSE;
18 : : gboolean tls = FALSE;
19 : :
20 : : static GOptionEntry cmd_entries[] = {
21 : : {"cancel", 'c', 0, G_OPTION_ARG_INT, &cancel_timeout,
22 : : "Cancel any op after the specified amount of seconds", NULL},
23 : : {"udp", 'u', 0, G_OPTION_ARG_NONE, &use_udp,
24 : : "Use udp instead of tcp", NULL},
25 : : {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
26 : : "Be verbose", NULL},
27 : : {"non-blocking", 'n', 0, G_OPTION_ARG_NONE, &non_blocking,
28 : : "Enable non-blocking i/o", NULL},
29 : : #ifdef G_OS_UNIX
30 : : {"unix", 'U', 0, G_OPTION_ARG_NONE, &unix_socket,
31 : : "Use a unix socket instead of IP", NULL},
32 : : #endif
33 : : {"timeout", 't', 0, G_OPTION_ARG_INT, &read_timeout,
34 : : "Time out reads after the specified number of seconds", NULL},
35 : : {"tls", 'T', 0, G_OPTION_ARG_NONE, &tls,
36 : : "Use TLS (SSL)", NULL},
37 : : G_OPTION_ENTRY_NULL
38 : : };
39 : :
40 : : #include "socket-common.c"
41 : :
42 : : static gboolean
43 : 0 : accept_certificate (GTlsClientConnection *conn,
44 : : GTlsCertificate *cert,
45 : : GTlsCertificateFlags errors,
46 : : gpointer user_data)
47 : : {
48 : 0 : g_print ("Certificate would have been rejected ( ");
49 : 0 : if (errors & G_TLS_CERTIFICATE_UNKNOWN_CA)
50 : 0 : g_print ("unknown-ca ");
51 : 0 : if (errors & G_TLS_CERTIFICATE_BAD_IDENTITY)
52 : 0 : g_print ("bad-identity ");
53 : 0 : if (errors & G_TLS_CERTIFICATE_NOT_ACTIVATED)
54 : 0 : g_print ("not-activated ");
55 : 0 : if (errors & G_TLS_CERTIFICATE_EXPIRED)
56 : 0 : g_print ("expired ");
57 : 0 : if (errors & G_TLS_CERTIFICATE_REVOKED)
58 : 0 : g_print ("revoked ");
59 : 0 : if (errors & G_TLS_CERTIFICATE_INSECURE)
60 : 0 : g_print ("insecure ");
61 : 0 : g_print (") but accepting anyway.\n");
62 : :
63 : 0 : return TRUE;
64 : : }
65 : :
66 : : static GTlsCertificate *
67 : 0 : lookup_client_certificate (GTlsClientConnection *conn,
68 : : GError **error)
69 : : {
70 : : GList *l, *accepted;
71 : : GList *c, *certificates;
72 : : GTlsDatabase *database;
73 : 0 : GTlsCertificate *certificate = NULL;
74 : : GTlsConnection *base;
75 : :
76 : 0 : accepted = g_tls_client_connection_get_accepted_cas (conn);
77 : 0 : for (l = accepted; l != NULL; l = g_list_next (l))
78 : : {
79 : 0 : base = G_TLS_CONNECTION (conn);
80 : 0 : database = g_tls_connection_get_database (base);
81 : 0 : certificates = g_tls_database_lookup_certificates_issued_by (database, l->data,
82 : : g_tls_connection_get_interaction (base),
83 : : G_TLS_DATABASE_LOOKUP_KEYPAIR,
84 : : NULL, error);
85 : 0 : if (error && *error)
86 : 0 : break;
87 : :
88 : 0 : if (certificates)
89 : 0 : certificate = g_object_ref (certificates->data);
90 : :
91 : 0 : for (c = certificates; c != NULL; c = g_list_next (c))
92 : 0 : g_object_unref (c->data);
93 : 0 : g_list_free (certificates);
94 : : }
95 : :
96 : 0 : for (l = accepted; l != NULL; l = g_list_next (l))
97 : 0 : g_byte_array_unref (l->data);
98 : 0 : g_list_free (accepted);
99 : :
100 : 0 : if (certificate == NULL && error && !*error)
101 : 0 : g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED,
102 : : "Server requested a certificate, but could not find relevant certificate in database.");
103 : 0 : return certificate;
104 : : }
105 : :
106 : : static gboolean
107 : 0 : make_connection (const char *argument,
108 : : GTlsCertificate *certificate,
109 : : GCancellable *cancellable,
110 : : GSocket **socket,
111 : : GSocketAddress **address,
112 : : GIOStream **connection,
113 : : GInputStream **istream,
114 : : GOutputStream **ostream,
115 : : GError **error)
116 : : {
117 : : GSocketType socket_type;
118 : : GSocketFamily socket_family;
119 : : GSocketAddressEnumerator *enumerator;
120 : : GSocketConnectable *connectable;
121 : : GSocketAddress *src_address;
122 : : GTlsInteraction *interaction;
123 : 0 : GError *err = NULL;
124 : :
125 : 0 : if (use_udp)
126 : 0 : socket_type = G_SOCKET_TYPE_DATAGRAM;
127 : : else
128 : 0 : socket_type = G_SOCKET_TYPE_STREAM;
129 : :
130 : 0 : if (unix_socket)
131 : 0 : socket_family = G_SOCKET_FAMILY_UNIX;
132 : : else
133 : 0 : socket_family = G_SOCKET_FAMILY_IPV4;
134 : :
135 : 0 : *socket = g_socket_new (socket_family, socket_type, 0, error);
136 : 0 : if (*socket == NULL)
137 : 0 : return FALSE;
138 : :
139 : 0 : if (read_timeout)
140 : 0 : g_socket_set_timeout (*socket, read_timeout);
141 : :
142 : 0 : if (unix_socket)
143 : : {
144 : : GSocketAddress *addr;
145 : :
146 : 0 : addr = socket_address_from_string (argument);
147 : 0 : if (addr == NULL)
148 : : {
149 : 0 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
150 : : "Could not parse '%s' as unix socket name", argument);
151 : 0 : return FALSE;
152 : : }
153 : 0 : connectable = G_SOCKET_CONNECTABLE (addr);
154 : : }
155 : : else
156 : : {
157 : 0 : connectable = g_network_address_parse (argument, 7777, error);
158 : 0 : if (connectable == NULL)
159 : 0 : return FALSE;
160 : : }
161 : :
162 : 0 : enumerator = g_socket_connectable_enumerate (connectable);
163 : : while (TRUE)
164 : : {
165 : 0 : *address = g_socket_address_enumerator_next (enumerator, cancellable, error);
166 : 0 : if (*address == NULL)
167 : : {
168 : 0 : if (error != NULL && *error == NULL)
169 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
170 : : "No more addresses to try");
171 : 0 : return FALSE;
172 : : }
173 : :
174 : 0 : if (g_socket_connect (*socket, *address, cancellable, &err))
175 : 0 : break;
176 : 0 : g_message ("Connection to %s failed: %s, trying next", socket_address_to_string (*address), err->message);
177 : 0 : g_clear_error (&err);
178 : :
179 : 0 : g_object_unref (*address);
180 : : }
181 : 0 : g_object_unref (enumerator);
182 : :
183 : 0 : g_print ("Connected to %s\n",
184 : : socket_address_to_string (*address));
185 : :
186 : 0 : src_address = g_socket_get_local_address (*socket, error);
187 : 0 : if (!src_address)
188 : : {
189 : 0 : g_prefix_error (error, "Error getting local address: ");
190 : 0 : return FALSE;
191 : : }
192 : :
193 : 0 : g_print ("local address: %s\n",
194 : : socket_address_to_string (src_address));
195 : 0 : g_object_unref (src_address);
196 : :
197 : 0 : if (use_udp)
198 : : {
199 : 0 : *connection = NULL;
200 : 0 : *istream = NULL;
201 : 0 : *ostream = NULL;
202 : : }
203 : : else
204 : 0 : *connection = G_IO_STREAM (g_socket_connection_factory_create_connection (*socket));
205 : :
206 : 0 : if (tls)
207 : : {
208 : : GIOStream *tls_conn;
209 : :
210 : 0 : tls_conn = g_tls_client_connection_new (*connection, connectable, error);
211 : 0 : if (!tls_conn)
212 : : {
213 : 0 : g_prefix_error (error, "Could not create TLS connection: ");
214 : 0 : return FALSE;
215 : : }
216 : :
217 : 0 : g_signal_connect (tls_conn, "accept-certificate",
218 : : G_CALLBACK (accept_certificate), NULL);
219 : :
220 : 0 : interaction = g_tls_console_interaction_new ();
221 : 0 : g_tls_connection_set_interaction (G_TLS_CONNECTION (tls_conn), interaction);
222 : 0 : g_object_unref (interaction);
223 : :
224 : 0 : if (certificate)
225 : 0 : g_tls_connection_set_certificate (G_TLS_CONNECTION (tls_conn), certificate);
226 : :
227 : 0 : g_object_unref (*connection);
228 : 0 : *connection = G_IO_STREAM (tls_conn);
229 : :
230 : 0 : if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn),
231 : : cancellable, error))
232 : : {
233 : 0 : g_prefix_error (error, "Error during TLS handshake: ");
234 : 0 : return FALSE;
235 : : }
236 : : }
237 : 0 : g_object_unref (connectable);
238 : :
239 : 0 : if (*connection)
240 : : {
241 : 0 : *istream = g_io_stream_get_input_stream (*connection);
242 : 0 : *ostream = g_io_stream_get_output_stream (*connection);
243 : : }
244 : :
245 : 0 : return TRUE;
246 : : }
247 : :
248 : : int
249 : 0 : main (int argc,
250 : : char *argv[])
251 : : {
252 : 0 : GSocket *socket = NULL;
253 : 0 : GSocketAddress *address = NULL;
254 : 0 : GError *error = NULL;
255 : : GOptionContext *context;
256 : : GCancellable *cancellable;
257 : 0 : GIOStream *connection = NULL;
258 : 0 : GInputStream *istream = NULL;
259 : 0 : GOutputStream *ostream = NULL;
260 : 0 : GSocketAddress *src_address = NULL;
261 : 0 : GTlsCertificate *certificate = NULL;
262 : : gint i;
263 : :
264 : 0 : address = NULL;
265 : 0 : connection = NULL;
266 : :
267 : 0 : context = g_option_context_new (" <hostname>[:port] - Test GSocket client stuff");
268 : 0 : g_option_context_add_main_entries (context, cmd_entries, NULL);
269 : 0 : if (!g_option_context_parse (context, &argc, &argv, &error))
270 : : {
271 : 0 : g_printerr ("%s: %s\n", argv[0], error->message);
272 : 0 : return 1;
273 : : }
274 : :
275 : 0 : if (argc != 2)
276 : : {
277 : 0 : g_printerr ("%s: %s\n", argv[0], "Need to specify hostname / unix socket name");
278 : 0 : return 1;
279 : : }
280 : :
281 : 0 : if (use_udp && tls)
282 : : {
283 : 0 : g_printerr ("DTLS (TLS over UDP) is not supported");
284 : 0 : return 1;
285 : : }
286 : :
287 : 0 : if (cancel_timeout)
288 : : {
289 : : GThread *thread;
290 : 0 : cancellable = g_cancellable_new ();
291 : 0 : thread = g_thread_new ("cancel", cancel_thread, cancellable);
292 : 0 : g_thread_unref (thread);
293 : : }
294 : : else
295 : : {
296 : 0 : cancellable = NULL;
297 : : }
298 : :
299 : 0 : loop = g_main_loop_new (NULL, FALSE);
300 : :
301 : 0 : for (i = 0; i < 2; i++)
302 : : {
303 : 0 : if (make_connection (argv[1], certificate, cancellable, &socket, &address,
304 : : &connection, &istream, &ostream, &error))
305 : 0 : break;
306 : :
307 : 0 : if (g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED))
308 : : {
309 : 0 : g_clear_error (&error);
310 : 0 : certificate = lookup_client_certificate (G_TLS_CLIENT_CONNECTION (connection), &error);
311 : 0 : if (certificate != NULL)
312 : 0 : continue;
313 : : }
314 : :
315 : 0 : g_printerr ("%s: %s", argv[0], error->message);
316 : 0 : return 1;
317 : : }
318 : :
319 : : /* TODO: Test non-blocking connect/handshake */
320 : 0 : if (non_blocking)
321 : 0 : g_socket_set_blocking (socket, FALSE);
322 : :
323 : : while (TRUE)
324 : 0 : {
325 : : gchar buffer[4096];
326 : : gssize size;
327 : : gsize to_send;
328 : :
329 : 0 : if (fgets (buffer, sizeof buffer, stdin) == NULL)
330 : 0 : break;
331 : :
332 : 0 : to_send = strlen (buffer);
333 : 0 : while (to_send > 0)
334 : : {
335 : 0 : if (use_udp)
336 : : {
337 : 0 : ensure_socket_condition (socket, G_IO_OUT, cancellable);
338 : 0 : size = g_socket_send_to (socket, address,
339 : : buffer, to_send,
340 : : cancellable, &error);
341 : : }
342 : : else
343 : : {
344 : 0 : ensure_connection_condition (connection, G_IO_OUT, cancellable);
345 : 0 : size = g_output_stream_write (ostream,
346 : : buffer, to_send,
347 : : cancellable, &error);
348 : : }
349 : :
350 : 0 : if (size < 0)
351 : : {
352 : 0 : if (g_error_matches (error,
353 : : G_IO_ERROR,
354 : : G_IO_ERROR_WOULD_BLOCK))
355 : : {
356 : 0 : g_print ("socket send would block, handling\n");
357 : 0 : g_error_free (error);
358 : 0 : error = NULL;
359 : 0 : continue;
360 : : }
361 : : else
362 : : {
363 : 0 : g_printerr ("Error sending to socket: %s\n",
364 : 0 : error->message);
365 : 0 : return 1;
366 : : }
367 : : }
368 : :
369 : 0 : g_print ("sent %" G_GSSIZE_FORMAT " bytes of data\n", size);
370 : :
371 : 0 : if (size == 0)
372 : : {
373 : 0 : g_printerr ("Unexpected short write\n");
374 : 0 : return 1;
375 : : }
376 : :
377 : 0 : to_send -= size;
378 : : }
379 : :
380 : 0 : if (use_udp)
381 : : {
382 : 0 : ensure_socket_condition (socket, G_IO_IN, cancellable);
383 : 0 : size = g_socket_receive_from (socket, &src_address,
384 : : buffer, sizeof buffer,
385 : : cancellable, &error);
386 : : }
387 : : else
388 : : {
389 : 0 : ensure_connection_condition (connection, G_IO_IN, cancellable);
390 : 0 : size = g_input_stream_read (istream,
391 : : buffer, sizeof buffer,
392 : : cancellable, &error);
393 : : }
394 : :
395 : 0 : if (size < 0)
396 : : {
397 : 0 : g_printerr ("Error receiving from socket: %s\n",
398 : 0 : error->message);
399 : 0 : return 1;
400 : : }
401 : :
402 : 0 : if (size == 0)
403 : 0 : break;
404 : :
405 : 0 : g_print ("received %" G_GSSIZE_FORMAT " bytes of data", size);
406 : 0 : if (use_udp)
407 : 0 : g_print (" from %s", socket_address_to_string (src_address));
408 : 0 : g_print ("\n");
409 : :
410 : 0 : if (verbose)
411 : 0 : g_print ("-------------------------\n"
412 : : "%.*s"
413 : : "-------------------------\n",
414 : : (int)size, buffer);
415 : :
416 : : }
417 : :
418 : 0 : g_print ("closing socket\n");
419 : :
420 : 0 : if (connection)
421 : : {
422 : 0 : if (!g_io_stream_close (connection, cancellable, &error))
423 : : {
424 : 0 : g_printerr ("Error closing connection: %s\n",
425 : 0 : error->message);
426 : 0 : return 1;
427 : : }
428 : 0 : g_object_unref (connection);
429 : : }
430 : : else
431 : : {
432 : 0 : if (!g_socket_close (socket, &error))
433 : : {
434 : 0 : g_printerr ("Error closing socket: %s\n",
435 : 0 : error->message);
436 : 0 : return 1;
437 : : }
438 : : }
439 : :
440 : 0 : g_object_unref (socket);
441 : 0 : g_object_unref (address);
442 : :
443 : 0 : return 0;
444 : : }
|