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 GSocket *
107 : 0 : make_socket (GSocketFamily socket_family, GSocketType socket_type, GError **error)
108 : : {
109 : 0 : GSocket *socket = g_socket_new (socket_family, socket_type, 0, error);
110 : :
111 : 0 : if (socket && read_timeout)
112 : 0 : g_socket_set_timeout (socket, read_timeout);
113 : :
114 : 0 : return socket;
115 : : }
116 : :
117 : : static gboolean
118 : 0 : make_connection (const char *argument,
119 : : GTlsCertificate *certificate,
120 : : GCancellable *cancellable,
121 : : GSocket **socket,
122 : : GSocketAddress **address,
123 : : GIOStream **connection,
124 : : GInputStream **istream,
125 : : GOutputStream **ostream,
126 : : GError **error)
127 : : {
128 : : GSocketType socket_type;
129 : : GSocketAddressEnumerator *enumerator;
130 : : GSocketConnectable *connectable;
131 : : GSocketAddress *src_address;
132 : : GTlsInteraction *interaction;
133 : 0 : GError *err = NULL;
134 : : char *socket_string;
135 : :
136 : 0 : if (use_udp)
137 : 0 : socket_type = G_SOCKET_TYPE_DATAGRAM;
138 : : else
139 : 0 : socket_type = G_SOCKET_TYPE_STREAM;
140 : :
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 : *socket = make_socket (unix_socket ? G_SOCKET_FAMILY_UNIX : g_socket_address_get_family (*address),
175 : : socket_type, error);
176 : 0 : if (*socket == NULL)
177 : : {
178 : 0 : g_object_unref (*address);
179 : 0 : g_object_unref (enumerator);
180 : 0 : return FALSE;
181 : : }
182 : :
183 : 0 : if (g_socket_connect (*socket, *address, cancellable, &err))
184 : 0 : break;
185 : 0 : socket_string = socket_address_to_string (*address);
186 : 0 : g_message ("Connection to %s failed: %s, trying next", socket_string, err->message);
187 : 0 : g_free (socket_string);
188 : 0 : g_clear_error (&err);
189 : :
190 : 0 : g_object_unref (*socket);
191 : 0 : g_object_unref (*address);
192 : : }
193 : 0 : g_object_unref (enumerator);
194 : :
195 : 0 : socket_string = socket_address_to_string (*address);
196 : 0 : g_print ("Connected to %s\n", socket_string);
197 : 0 : g_free (socket_string);
198 : :
199 : 0 : src_address = g_socket_get_local_address (*socket, error);
200 : 0 : if (!src_address)
201 : : {
202 : 0 : g_prefix_error (error, "Error getting local address: ");
203 : 0 : return FALSE;
204 : : }
205 : :
206 : 0 : socket_string = socket_address_to_string (src_address);
207 : 0 : g_print ("local address: %s\n", socket_string);
208 : 0 : g_free (socket_string);
209 : 0 : g_object_unref (src_address);
210 : :
211 : 0 : if (use_udp)
212 : : {
213 : 0 : *connection = NULL;
214 : 0 : *istream = NULL;
215 : 0 : *ostream = NULL;
216 : : }
217 : : else
218 : 0 : *connection = G_IO_STREAM (g_socket_connection_factory_create_connection (*socket));
219 : :
220 : 0 : if (tls)
221 : : {
222 : : GIOStream *tls_conn;
223 : :
224 : 0 : tls_conn = g_tls_client_connection_new (*connection, connectable, error);
225 : 0 : if (!tls_conn)
226 : : {
227 : 0 : g_prefix_error (error, "Could not create TLS connection: ");
228 : 0 : return FALSE;
229 : : }
230 : :
231 : 0 : g_signal_connect (tls_conn, "accept-certificate",
232 : : G_CALLBACK (accept_certificate), NULL);
233 : :
234 : 0 : interaction = g_tls_console_interaction_new ();
235 : 0 : g_tls_connection_set_interaction (G_TLS_CONNECTION (tls_conn), interaction);
236 : 0 : g_object_unref (interaction);
237 : :
238 : 0 : if (certificate)
239 : 0 : g_tls_connection_set_certificate (G_TLS_CONNECTION (tls_conn), certificate);
240 : :
241 : 0 : g_object_unref (*connection);
242 : 0 : *connection = G_IO_STREAM (tls_conn);
243 : :
244 : 0 : if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn),
245 : : cancellable, error))
246 : : {
247 : 0 : g_prefix_error (error, "Error during TLS handshake: ");
248 : 0 : return FALSE;
249 : : }
250 : : }
251 : 0 : g_object_unref (connectable);
252 : :
253 : 0 : if (*connection)
254 : : {
255 : 0 : *istream = g_io_stream_get_input_stream (*connection);
256 : 0 : *ostream = g_io_stream_get_output_stream (*connection);
257 : : }
258 : :
259 : 0 : return TRUE;
260 : : }
261 : :
262 : : int
263 : 0 : main (int argc,
264 : : char *argv[])
265 : : {
266 : 0 : GSocket *socket = NULL;
267 : 0 : GSocketAddress *address = NULL;
268 : 0 : GError *error = NULL;
269 : : GOptionContext *context;
270 : : GCancellable *cancellable;
271 : 0 : GIOStream *connection = NULL;
272 : 0 : GInputStream *istream = NULL;
273 : 0 : GOutputStream *ostream = NULL;
274 : 0 : GSocketAddress *src_address = NULL;
275 : 0 : GTlsCertificate *certificate = NULL;
276 : : gint i;
277 : :
278 : 0 : address = NULL;
279 : 0 : connection = NULL;
280 : :
281 : 0 : context = g_option_context_new (" <hostname>[:port] - Test GSocket client stuff");
282 : 0 : g_option_context_add_main_entries (context, cmd_entries, NULL);
283 : 0 : if (!g_option_context_parse (context, &argc, &argv, &error))
284 : : {
285 : 0 : g_printerr ("%s: %s\n", argv[0], error->message);
286 : 0 : return 1;
287 : : }
288 : :
289 : 0 : if (argc != 2)
290 : : {
291 : 0 : g_printerr ("%s: %s\n", argv[0], "Need to specify hostname / unix socket name");
292 : 0 : return 1;
293 : : }
294 : :
295 : 0 : if (use_udp && tls)
296 : : {
297 : 0 : g_printerr ("DTLS (TLS over UDP) is not supported");
298 : 0 : return 1;
299 : : }
300 : :
301 : 0 : if (cancel_timeout)
302 : : {
303 : : GThread *thread;
304 : 0 : cancellable = g_cancellable_new ();
305 : 0 : thread = g_thread_new ("cancel", cancel_thread, cancellable);
306 : 0 : g_thread_unref (thread);
307 : : }
308 : : else
309 : : {
310 : 0 : cancellable = NULL;
311 : : }
312 : :
313 : 0 : loop = g_main_loop_new (NULL, FALSE);
314 : :
315 : 0 : for (i = 0; i < 2; i++)
316 : : {
317 : 0 : if (make_connection (argv[1], certificate, cancellable, &socket, &address,
318 : : &connection, &istream, &ostream, &error))
319 : 0 : break;
320 : :
321 : 0 : if (g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED))
322 : : {
323 : 0 : g_clear_error (&error);
324 : 0 : certificate = lookup_client_certificate (G_TLS_CLIENT_CONNECTION (connection), &error);
325 : 0 : if (certificate != NULL)
326 : 0 : continue;
327 : : }
328 : :
329 : 0 : g_printerr ("%s: %s", argv[0], error->message);
330 : 0 : return 1;
331 : : }
332 : :
333 : : /* TODO: Test non-blocking connect/handshake */
334 : 0 : if (non_blocking)
335 : 0 : g_socket_set_blocking (socket, FALSE);
336 : :
337 : : while (TRUE)
338 : 0 : {
339 : : gchar buffer[4096];
340 : : gssize size;
341 : : gsize to_send;
342 : :
343 : 0 : if (fgets (buffer, sizeof buffer, stdin) == NULL)
344 : 0 : break;
345 : :
346 : 0 : to_send = strlen (buffer);
347 : 0 : while (to_send > 0)
348 : : {
349 : 0 : if (use_udp)
350 : : {
351 : 0 : ensure_socket_condition (socket, G_IO_OUT, cancellable);
352 : 0 : size = g_socket_send_to (socket, address,
353 : : buffer, to_send,
354 : : cancellable, &error);
355 : : }
356 : : else
357 : : {
358 : 0 : ensure_connection_condition (connection, G_IO_OUT, cancellable);
359 : 0 : size = g_output_stream_write (ostream,
360 : : buffer, to_send,
361 : : cancellable, &error);
362 : : }
363 : :
364 : 0 : if (size < 0)
365 : : {
366 : 0 : if (g_error_matches (error,
367 : : G_IO_ERROR,
368 : : G_IO_ERROR_WOULD_BLOCK))
369 : : {
370 : 0 : g_print ("socket send would block, handling\n");
371 : 0 : g_error_free (error);
372 : 0 : error = NULL;
373 : 0 : continue;
374 : : }
375 : : else
376 : : {
377 : 0 : g_printerr ("Error sending to socket: %s\n",
378 : 0 : error->message);
379 : 0 : return 1;
380 : : }
381 : : }
382 : :
383 : 0 : g_print ("sent %" G_GSSIZE_FORMAT " bytes of data\n", size);
384 : :
385 : 0 : if (size == 0)
386 : : {
387 : 0 : g_printerr ("Unexpected short write\n");
388 : 0 : return 1;
389 : : }
390 : :
391 : 0 : to_send -= size;
392 : : }
393 : :
394 : 0 : if (use_udp)
395 : : {
396 : 0 : ensure_socket_condition (socket, G_IO_IN, cancellable);
397 : 0 : size = g_socket_receive_from (socket, &src_address,
398 : : buffer, sizeof buffer,
399 : : cancellable, &error);
400 : : }
401 : : else
402 : : {
403 : 0 : ensure_connection_condition (connection, G_IO_IN, cancellable);
404 : 0 : size = g_input_stream_read (istream,
405 : : buffer, sizeof buffer,
406 : : cancellable, &error);
407 : : }
408 : :
409 : 0 : if (size < 0)
410 : : {
411 : 0 : g_printerr ("Error receiving from socket: %s\n",
412 : 0 : error->message);
413 : 0 : return 1;
414 : : }
415 : :
416 : 0 : if (size == 0)
417 : 0 : break;
418 : :
419 : 0 : g_print ("received %" G_GSSIZE_FORMAT " bytes of data", size);
420 : 0 : if (use_udp)
421 : 0 : g_print (" from %s", socket_address_to_string (src_address));
422 : 0 : g_print ("\n");
423 : :
424 : 0 : if (verbose)
425 : 0 : g_print ("-------------------------\n"
426 : : "%.*s"
427 : : "-------------------------\n",
428 : : (int)size, buffer);
429 : :
430 : : }
431 : :
432 : 0 : g_print ("closing socket\n");
433 : :
434 : 0 : if (connection)
435 : : {
436 : 0 : if (!g_io_stream_close (connection, cancellable, &error))
437 : : {
438 : 0 : g_printerr ("Error closing connection: %s\n",
439 : 0 : error->message);
440 : 0 : return 1;
441 : : }
442 : 0 : g_object_unref (connection);
443 : : }
444 : : else
445 : : {
446 : 0 : if (!g_socket_close (socket, &error))
447 : : {
448 : 0 : g_printerr ("Error closing socket: %s\n",
449 : 0 : error->message);
450 : 0 : return 1;
451 : : }
452 : : }
453 : :
454 : 0 : g_object_unref (socket);
455 : 0 : g_object_unref (address);
456 : :
457 : 0 : return 0;
458 : : }
|