blob: 1fc336e9885d222f76771fb585812fea6b55e6ae [file] [log] [blame]
Brian Waters13d96012017-12-08 16:53:31 -06001/*********************************************************************************************************
2* Software License Agreement (BSD License) *
3* Author: Sebastien Decugis <sdecugis@freediameter.net> *
4* *
5* Copyright (c) 2015, WIDE Project and NICT *
6* All rights reserved. *
7* *
8* Redistribution and use of this software in source and binary forms, with or without modification, are *
9* permitted provided that the following conditions are met: *
10* *
11* * Redistributions of source code must retain the above *
12* copyright notice, this list of conditions and the *
13* following disclaimer. *
14* *
15* * Redistributions in binary form must reproduce the above *
16* copyright notice, this list of conditions and the *
17* following disclaimer in the documentation and/or other *
18* materials provided with the distribution. *
19* *
20* * Neither the name of the WIDE Project or NICT nor the *
21* names of its contributors may be used to endorse or *
22* promote products derived from this software without *
23* specific prior written permission of WIDE Project and *
24* NICT. *
25* *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34*********************************************************************************************************/
35
36#include "fdcore-internal.h"
37#include "cnxctx.h"
38
39#include <net/if.h>
40#include <ifaddrs.h> /* for getifaddrs */
41#include <sys/uio.h> /* writev */
42
43/* The maximum size of Diameter message we accept to receive (<= 2^24) to avoid too big mallocs in case of trashed headers */
44#ifndef DIAMETER_MSG_SIZE_MAX
45#define DIAMETER_MSG_SIZE_MAX 65535 /* in bytes */
46#endif /* DIAMETER_MSG_SIZE_MAX */
47
48
49/* Connections contexts (cnxctx) in freeDiameter are wrappers around the sockets and TLS operations .
50 * They are used to hide the details of the processing to the higher layers of the daemon.
51 * They are always oriented on connections (TCP or SCTP), connectionless modes (UDP or SCTP) are not supported.
52 */
53
54/* Lifetime of a cnxctx object:
55 * 1) Creation
56 * a) a server socket:
57 * - create the object with fd_cnx_serv_tcp or fd_cnx_serv_sctp
58 * - start listening incoming connections: fd_cnx_serv_listen
59 * - accept new clients with fd_cnx_serv_accept.
60 * b) a client socket:
61 * - connect to a remote server with fd_cnx_cli_connect
62 *
63 * 2) Initialization
64 * - if TLS is started first, call fd_cnx_handshake
65 * - otherwise to receive clear messages, call fd_cnx_start_clear. fd_cnx_handshake can be called later.
66 *
67 * 3) Usage
68 * - fd_cnx_receive, fd_cnx_send : exchange messages on this connection (send is synchronous, receive is not, but blocking).
69 * - fd_cnx_recv_setaltfifo : when a message is received, the event is sent to an external fifo list. fd_cnx_receive does not work when the alt_fifo is set.
70 * - fd_cnx_getid : retrieve a descriptive string for the connection (for debug)
71 * - fd_cnx_getremoteid : identification of the remote peer (IP address or fqdn)
72 * - fd_cnx_getcred : get the remote peer TLS credentials, after handshake
73 *
74 * 4) End
75 * - fd_cnx_destroy
76 */
77
78/*******************************************/
79/* Creation of a connection object */
80/*******************************************/
81
82/* Initialize a context structure */
83static struct cnxctx * fd_cnx_init(int full)
84{
85 struct cnxctx * conn = NULL;
86
87 TRACE_ENTRY("%d", full);
88
89 CHECK_MALLOC_DO( conn = malloc(sizeof(struct cnxctx)), return NULL );
90 memset(conn, 0, sizeof(struct cnxctx));
91
92 if (full) {
93 CHECK_FCT_DO( fd_fifo_new ( &conn->cc_incoming, 5 ), return NULL );
94 }
95
96 return conn;
97}
98
99#define CC_ID_HDR "{----} "
100
101/* Create and bind a server socket to the given endpoint and port */
102struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep)
103{
104 struct cnxctx * cnx = NULL;
105 sSS dummy;
106 sSA * sa = (sSA *) &dummy;
107
108 TRACE_ENTRY("%hu %d %p", port, family, ep);
109
110 CHECK_PARAMS_DO( port, return NULL );
111 CHECK_PARAMS_DO( ep || family, return NULL );
112 CHECK_PARAMS_DO( (! family) || (family == AF_INET) || (family == AF_INET6), return NULL );
113 CHECK_PARAMS_DO( (! ep) || (ep->ss.ss_family == AF_INET) || (ep->ss.ss_family == AF_INET6), return NULL );
114 CHECK_PARAMS_DO( (! ep) || (!family) || (ep->ss.ss_family == family), return NULL );
115
116 /* The connection object */
117 CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL );
118
119 /* Prepare the socket address information */
120 if (ep) {
121 memcpy(sa, &ep->ss, sizeof(sSS));
122 } else {
123 memset(&dummy, 0, sizeof(dummy));
124 sa->sa_family = family;
125 }
126 if (sa->sa_family == AF_INET) {
127 ((sSA4 *)sa)->sin_port = htons(port);
128 cnx->cc_family = AF_INET;
129 } else {
130 ((sSA6 *)sa)->sin6_port = htons(port);
131 cnx->cc_family = AF_INET6;
132 }
133
134 /* Create the socket */
135 CHECK_FCT_DO( fd_tcp_create_bind_server( &cnx->cc_socket, sa, sSAlen(sa) ), goto error );
136
137 /* Generate the name for the connection object */
138 {
139 char addrbuf[INET6_ADDRSTRLEN];
140 int rc;
141 rc = getnameinfo(sa, sSAlen(sa), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
142 if (rc)
143 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
144 snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "TCP srv [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket);
145 }
146
147 cnx->cc_proto = IPPROTO_TCP;
148
149 return cnx;
150
151error:
152 fd_cnx_destroy(cnx);
153 return NULL;
154}
155
156/* Same function for SCTP, with a list of local endpoints to bind to */
157struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list)
158{
159#ifdef DISABLE_SCTP
160 TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled...");
161 ASSERT(0);
162 CHECK_FCT_DO( ENOTSUP, );
163 return NULL;
164#else /* DISABLE_SCTP */
165 struct cnxctx * cnx = NULL;
166
167 TRACE_ENTRY("%hu %p", port, ep_list);
168
169 CHECK_PARAMS_DO( port, return NULL );
170
171 /* The connection object */
172 CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL );
173
174 if (fd_g_config->cnf_flags.no_ip6) {
175 cnx->cc_family = AF_INET;
176 } else {
177 cnx->cc_family = AF_INET6; /* can create socket for both IP and IPv6 */
178 }
179
180 /* Create the socket */
181 CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, cnx->cc_family, ep_list, port ), goto error );
182
183 /* Generate the name for the connection object */
184 snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "SCTP srv :%hu (%d)", port, cnx->cc_socket);
185
186 cnx->cc_proto = IPPROTO_SCTP;
187
188 return cnx;
189
190error:
191 fd_cnx_destroy(cnx);
192 return NULL;
193#endif /* DISABLE_SCTP */
194}
195
196/* Allow clients to connect on the server socket */
197int fd_cnx_serv_listen(struct cnxctx * conn)
198{
199 CHECK_PARAMS( conn );
200
201 switch (conn->cc_proto) {
202 case IPPROTO_TCP:
203 CHECK_FCT(fd_tcp_listen(conn->cc_socket));
204 break;
205
206#ifndef DISABLE_SCTP
207 case IPPROTO_SCTP:
208 CHECK_FCT(fd_sctp_listen(conn->cc_socket));
209 break;
210#endif /* DISABLE_SCTP */
211
212 default:
213 CHECK_PARAMS(0);
214 }
215
216 return 0;
217}
218
219/* Accept a client (blocking until a new client connects) -- cancelable */
220struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv)
221{
222 struct cnxctx * cli = NULL;
223 sSS ss;
224 socklen_t ss_len = sizeof(ss);
225 int cli_sock = 0;
226
227 TRACE_ENTRY("%p", serv);
228 CHECK_PARAMS_DO(serv, return NULL);
229
230 /* Accept the new connection -- this is blocking until new client enters or until cancellation */
231 CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL );
232
233 CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); close(cli_sock); return NULL; } );
234 cli->cc_socket = cli_sock;
235 cli->cc_family = serv->cc_family;
236 cli->cc_proto = serv->cc_proto;
237
238 /* Set the timeout */
239 fd_cnx_s_setto(cli->cc_socket);
240
241 /* Generate the name for the connection object */
242 {
243 char addrbuf[INET6_ADDRSTRLEN];
244 char portbuf[10];
245 int rc;
246
247 rc = getnameinfo((sSA *)&ss, ss_len, addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
248 if (rc) {
249 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
250 portbuf[0] = '\0';
251 }
252
253 /* Numeric values for debug... */
254 snprintf(cli->cc_id, sizeof(cli->cc_id), CC_ID_HDR "%s from [%s]:%s (%d<-%d)",
255 IPPROTO_NAME(cli->cc_proto), addrbuf, portbuf, serv->cc_socket, cli->cc_socket);
256
257
258 /* ...Name for log messages */
259 rc = getnameinfo((sSA *)&ss, ss_len, cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0);
260 if (rc)
261 snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc));
262 }
263
264 LOG_D("Incoming connection: '%s' <- '%s' {%s}", fd_cnx_getid(serv), cli->cc_remid, cli->cc_id);
265
266#ifndef DISABLE_SCTP
267 /* SCTP-specific handlings */
268 if (cli->cc_proto == IPPROTO_SCTP) {
269 /* Retrieve the number of streams */
270 CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out, NULL ), {fd_cnx_destroy(cli); return NULL;} );
271 if (cli->cc_sctp_para.str_out < cli->cc_sctp_para.str_in)
272 cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_out;
273 else
274 cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_in;
275
276 LOG_A( "%s : client '%s' (SCTP:%d, %d/%d streams)", fd_cnx_getid(serv), fd_cnx_getid(cli), cli->cc_socket, cli->cc_sctp_para.str_in, cli->cc_sctp_para.str_out);
277 }
278#endif /* DISABLE_SCTP */
279
280 return cli;
281}
282
283/* Client side: connect to a remote server -- cancelable */
284struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa /* contains the port already */, socklen_t addrlen)
285{
286 int sock = 0;
287 struct cnxctx * cnx = NULL;
288 char sa_buf[sSA_DUMP_STRLEN];
289
290 TRACE_ENTRY("%p %d", sa, addrlen);
291 CHECK_PARAMS_DO( sa && addrlen, return NULL );
292
293 fd_sa_sdump_numeric(sa_buf, sa);
294
295 LOG_D("Connecting to TCP %s...", sa_buf);
296
297 /* Create the socket and connect, which can take some time and/or fail */
298 {
299 int ret = fd_tcp_client( &sock, sa, addrlen );
300 if (ret != 0) {
301 LOG_D("TCP connection to %s failed: %s", sa_buf, strerror(ret));
302 return NULL;
303 }
304 }
305
306 /* Once the socket is created successfuly, prepare the remaining of the cnx */
307 CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); close(sock); return NULL; } );
308
309 cnx->cc_socket = sock;
310 cnx->cc_family = sa->sa_family;
311 cnx->cc_proto = IPPROTO_TCP;
312
313 /* Set the timeout */
314 fd_cnx_s_setto(cnx->cc_socket);
315
316 /* Generate the names for the object */
317 {
318 int rc;
319
320 snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "TCP,#%d->%s", cnx->cc_socket, sa_buf);
321
322 /* ...Name for log messages */
323 rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
324 if (rc)
325 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc));
326 }
327
328 LOG_A("TCP connection to %s succeed (socket:%d).", sa_buf, sock);
329
330 return cnx;
331}
332
333/* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx for how they are used) */
334struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list)
335{
336#ifdef DISABLE_SCTP
337 TRACE_DEBUG(INFO, "This function should never be called when SCTP is disabled...");
338 ASSERT(0);
339 CHECK_FCT_DO( ENOTSUP, );
340 return NULL;
341#else /* DISABLE_SCTP */
342 int sock = 0;
343 struct cnxctx * cnx = NULL;
344 char sa_buf[sSA_DUMP_STRLEN];
345 sSS primary;
346
347 TRACE_ENTRY("%p", list);
348 CHECK_PARAMS_DO( list && !FD_IS_LIST_EMPTY(list), return NULL );
349
350 fd_sa_sdump_numeric(sa_buf, &((struct fd_endpoint *)(list->next))->sa);
351
352 LOG_D("Connecting to SCTP %s:%hu...", sa_buf, port);
353
354 {
355 int ret = fd_sctp_client( &sock, no_ip6, port, list );
356 if (ret != 0) {
357 LOG_D("SCTP connection to [%s,...] failed: %s", sa_buf, strerror(ret));
358 return NULL;
359 }
360 }
361
362 /* Once the socket is created successfuly, prepare the remaining of the cnx */
363 CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); close(sock); return NULL; } );
364
365 cnx->cc_socket = sock;
366 cnx->cc_family = no_ip6 ? AF_INET : AF_INET6;
367 cnx->cc_proto = IPPROTO_SCTP;
368
369 /* Set the timeout */
370 fd_cnx_s_setto(cnx->cc_socket);
371
372 /* Retrieve the number of streams and primary address */
373 CHECK_FCT_DO( fd_sctp_get_str_info( sock, &cnx->cc_sctp_para.str_in, &cnx->cc_sctp_para.str_out, &primary ), goto error );
374 if (cnx->cc_sctp_para.str_out < cnx->cc_sctp_para.str_in)
375 cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_out;
376 else
377 cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_in;
378
379 fd_sa_sdump_numeric(sa_buf, (sSA *)&primary);
380
381 /* Generate the names for the object */
382 {
383 int rc;
384
385 snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "SCTP,#%d->%s", cnx->cc_socket, sa_buf);
386
387 /* ...Name for log messages */
388 rc = getnameinfo((sSA *)&primary, sSAlen(&primary), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
389 if (rc)
390 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc));
391 }
392
393 LOG_A("SCTP connection to %s succeed (socket:%d, %d/%d streams).", sa_buf, sock, cnx->cc_sctp_para.str_in, cnx->cc_sctp_para.str_out);
394
395 return cnx;
396
397error:
398 fd_cnx_destroy(cnx);
399 return NULL;
400#endif /* DISABLE_SCTP */
401}
402
403/* Return a string describing the connection, for debug */
404char * fd_cnx_getid(struct cnxctx * conn)
405{
406 CHECK_PARAMS_DO( conn, return "" );
407 return conn->cc_id;
408}
409
410/* Return the protocol of a connection */
411int fd_cnx_getproto(struct cnxctx * conn)
412{
413 CHECK_PARAMS_DO( conn, return 0 );
414 return conn->cc_proto;
415}
416
417/* Set the hostname to check during handshake */
418void fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn)
419{
420 CHECK_PARAMS_DO( conn, return );
421 conn->cc_tls_para.cn = hn;
422}
423
424/* We share a lock with many threads but we hold it only very short time so it is OK */
425static pthread_mutex_t state_lock = PTHREAD_MUTEX_INITIALIZER;
426uint32_t fd_cnx_getstate(struct cnxctx * conn)
427{
428 uint32_t st;
429 CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
430 st = conn->cc_state;
431 CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
432 return st;
433}
434int fd_cnx_teststate(struct cnxctx * conn, uint32_t flag)
435{
436 uint32_t st;
437 CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
438 st = conn->cc_state;
439 CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
440 return st & flag;
441}
442void fd_cnx_update_id(struct cnxctx * conn) {
443 if (conn->cc_state & CC_STATUS_CLOSING)
444 conn->cc_id[1] = 'C';
445 else
446 conn->cc_id[1] = '-';
447
448 if (conn->cc_state & CC_STATUS_ERROR)
449 conn->cc_id[2] = 'E';
450 else
451 conn->cc_id[2] = '-';
452
453 if (conn->cc_state & CC_STATUS_SIGNALED)
454 conn->cc_id[3] = 'S';
455 else
456 conn->cc_id[3] = '-';
457
458 if (conn->cc_state & CC_STATUS_TLS)
459 conn->cc_id[4] = 'T';
460 else
461 conn->cc_id[4] = '-';
462}
463void fd_cnx_addstate(struct cnxctx * conn, uint32_t orstate)
464{
465 CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
466 conn->cc_state |= orstate;
467 fd_cnx_update_id(conn);
468 CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
469}
470void fd_cnx_setstate(struct cnxctx * conn, uint32_t abstate)
471{
472 CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
473 conn->cc_state = abstate;
474 fd_cnx_update_id(conn);
475 CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
476}
477
478
479/* Return the TLS state of a connection */
480int fd_cnx_getTLS(struct cnxctx * conn)
481{
482 CHECK_PARAMS_DO( conn, return 0 );
483 return fd_cnx_teststate(conn, CC_STATUS_TLS);
484}
485
486/* Mark the connection to tell if OOO delivery is permitted (only for SCTP) */
487int fd_cnx_unordered_delivery(struct cnxctx * conn, int is_allowed)
488{
489 CHECK_PARAMS( conn );
490 conn->cc_sctp_para.unordered = is_allowed;
491 return 0;
492}
493
494/* Return true if the connection supports unordered delivery of messages */
495int fd_cnx_is_unordered_delivery_supported(struct cnxctx * conn)
496{
497 CHECK_PARAMS_DO( conn, return 0 );
498 #ifndef DISABLE_SCTP
499 if (conn->cc_proto == IPPROTO_SCTP)
500 return (conn->cc_sctp_para.str_out > 1);
501 #endif /* DISABLE_SCTP */
502 return 0;
503}
504
505
506/* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */
507int fd_cnx_getremoteeps(struct cnxctx * conn, struct fd_list * eps)
508{
509 TRACE_ENTRY("%p %p", conn, eps);
510 CHECK_PARAMS(conn && eps);
511
512 /* Check we have a full connection object, not a listening socket (with no remote) */
513 CHECK_PARAMS( conn->cc_incoming );
514
515 /* Retrieve the peer endpoint(s) of the connection */
516 switch (conn->cc_proto) {
517 case IPPROTO_TCP: {
518 sSS ss;
519 socklen_t sl;
520 CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl));
521 CHECK_FCT(fd_ep_add_merge( eps, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY ));
522 }
523 break;
524
525 #ifndef DISABLE_SCTP
526 case IPPROTO_SCTP: {
527 CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, eps));
528 }
529 break;
530 #endif /* DISABLE_SCTP */
531
532 default:
533 CHECK_PARAMS(0);
534 }
535
536 return 0;
537}
538
539/* Get a string describing the remote peer address (ip address or fqdn) */
540char * fd_cnx_getremoteid(struct cnxctx * conn)
541{
542 CHECK_PARAMS_DO( conn, return "" );
543 return conn->cc_remid;
544}
545
546static int fd_cnx_may_dtls(struct cnxctx * conn);
547
548/* Get a short string representing the connection */
549int fd_cnx_proto_info(struct cnxctx * conn, char * buf, size_t len)
550{
551 CHECK_PARAMS( conn );
552
553 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) {
554 snprintf(buf, len, "%s,%s,soc#%d", IPPROTO_NAME(conn->cc_proto), fd_cnx_may_dtls(conn) ? "DTLS" : "TLS", conn->cc_socket);
555 } else {
556 snprintf(buf, len, "%s,soc#%d", IPPROTO_NAME(conn->cc_proto), conn->cc_socket);
557 }
558
559 return 0;
560}
561
562/* Retrieve a list of all IP addresses of the local system from the kernel, using getifaddrs */
563int fd_cnx_get_local_eps(struct fd_list * list)
564{
565 struct ifaddrs *iflist, *cur;
566
567 CHECK_SYS(getifaddrs(&iflist));
568
569 for (cur = iflist; cur != NULL; cur = cur->ifa_next) {
570 if (cur->ifa_flags & IFF_LOOPBACK)
571 continue;
572
573 if (cur->ifa_addr == NULL) /* may happen with ppp interfaces */
574 continue;
575
576 if (fd_g_config->cnf_flags.no_ip4 && (cur->ifa_addr->sa_family == AF_INET))
577 continue;
578
579 if (fd_g_config->cnf_flags.no_ip6 && (cur->ifa_addr->sa_family == AF_INET6))
580 continue;
581
582 CHECK_FCT(fd_ep_add_merge( list, cur->ifa_addr, sSAlen(cur->ifa_addr), EP_FL_LL ));
583 }
584
585 freeifaddrs(iflist);
586
587 return 0;
588}
589
590
591/**************************************/
592/* Use of a connection object */
593/**************************************/
594
595/* An error occurred on the socket */
596void fd_cnx_markerror(struct cnxctx * conn)
597{
598 TRACE_ENTRY("%p", conn);
599 CHECK_PARAMS_DO( conn, goto fatal );
600
601 TRACE_DEBUG(FULL, "Error flag set for socket %d (%s, %s)", conn->cc_socket, conn->cc_id, conn->cc_remid);
602
603 /* Mark the error */
604 fd_cnx_addstate(conn, CC_STATUS_ERROR);
605
606 /* Report the error if not reported yet, and not closing */
607 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING | CC_STATUS_SIGNALED )) {
608 TRACE_DEBUG(FULL, "Sending FDEVP_CNX_ERROR event");
609 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_ERROR, 0, NULL), goto fatal);
610 fd_cnx_addstate(conn, CC_STATUS_SIGNALED);
611 }
612
613 return;
614fatal:
615 /* An unrecoverable error occurred, stop the daemon */
616 ASSERT(0);
617 CHECK_FCT_DO(fd_core_shutdown(), );
618}
619
620/* Set the timeout option on the socket */
621void fd_cnx_s_setto(int sock)
622{
623 struct timeval tv;
624
625 /* Set a timeout on the socket so that in any case we are not stuck waiting for something */
626 memset(&tv, 0, sizeof(tv));
627 tv.tv_usec = 100000L; /* 100ms, to react quickly to head-of-the-line blocking. */
628 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), );
629 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), );
630}
631
632
633#ifdef GNUTLS_VERSION_300
634/* The pull_timeout function for gnutls */
635static int fd_cnx_s_select (struct cnxctx * conn, unsigned int ms)
636{
637 fd_set rfds;
638 struct timeval tv;
639
640 FD_ZERO (&rfds);
641 FD_SET (conn->cc_socket, &rfds);
642
643 tv.tv_sec = ms / 1000;
644 tv.tv_usec = (ms * 1000) % 1000000;
645
646 return select (conn->cc_socket + 1, &rfds, NULL, NULL, &tv);
647}
648#endif /* GNUTLS_VERSION_300 */
649
650/* A recv-like function, taking a cnxctx object instead of socket as entry. We use it to quickly react to timeouts without traversing GNUTLS wrapper each time */
651ssize_t fd_cnx_s_recv(struct cnxctx * conn, void *buffer, size_t length)
652{
653 ssize_t ret = 0;
654 int timedout = 0;
655again:
656 ret = recv(conn->cc_socket, buffer, length, 0);
657 /* Handle special case of timeout / interrupts */
658 if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) {
659 pthread_testcancel();
660 if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING ))
661 goto again; /* don't care, just ignore */
662 if (!timedout) {
663 timedout ++; /* allow for one timeout while closing */
664 goto again;
665 }
666 }
667
668 /* Mark the error */
669 if (ret <= 0) {
670 CHECK_SYS_DO(ret, /* continue, this is only used to log the error here */);
671 fd_cnx_markerror(conn);
672 }
673
674 return ret;
675}
676
677/* Send */
678static ssize_t fd_cnx_s_sendv(struct cnxctx * conn, const struct iovec * iov, int iovcnt)
679{
680 ssize_t ret = 0;
681 struct timespec ts, now;
682 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), return -1 );
683again:
684 ret = writev(conn->cc_socket, iov, iovcnt);
685 /* Handle special case of timeout */
686 if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) {
687 ret = -errno;
688 pthread_testcancel();
689
690 /* Check how much time we were blocked for this sending. */
691 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), return -1 );
692 if ( ((now.tv_sec - ts.tv_sec) * 1000 + ((now.tv_nsec - ts.tv_nsec) / 1000000L)) > MAX_HOTL_BLOCKING_TIME) {
693 LOG_D("Unable to send any data for %dms, closing the connection", MAX_HOTL_BLOCKING_TIME);
694 } else if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING )) {
695 goto again; /* don't care, just ignore */
696 }
697
698 /* propagate the error */
699 errno = -ret;
700 ret = -1;
701 CHECK_SYS_DO(ret, /* continue */);
702 }
703
704 /* Mark the error */
705 if (ret <= 0)
706 fd_cnx_markerror(conn);
707
708 return ret;
709}
710
711/* Send, for older GNUTLS */
712#ifndef GNUTLS_VERSION_212
713static ssize_t fd_cnx_s_send(struct cnxctx * conn, const void *buffer, size_t length)
714{
715 struct iovec iov;
716 iov.iov_base = (void *)buffer;
717 iov.iov_len = length;
718 return fd_cnx_s_sendv(conn, &iov, 1);
719}
720#endif /* GNUTLS_VERSION_212 */
721
722#define ALIGNOF(t) ((char *)(&((struct { char c; t _h; } *)0)->_h) - (char *)0) /* Could use __alignof__(t) on some systems but this is more portable probably */
723#define PMDL_PADDED(len) ( ((len) + ALIGNOF(struct fd_msg_pmdl) - 1) & ~(ALIGNOF(struct fd_msg_pmdl) - 1) )
724
725size_t fd_msg_pmdl_sizewithoverhead(size_t datalen)
726{
727 return PMDL_PADDED(datalen) + sizeof(struct fd_msg_pmdl);
728}
729
730struct fd_msg_pmdl * fd_msg_pmdl_get_inbuf(uint8_t * buf, size_t datalen)
731{
732 return (struct fd_msg_pmdl *)(buf + PMDL_PADDED(datalen));
733}
734
735static int fd_cnx_init_msg_buffer(uint8_t * buffer, size_t expected_len, struct fd_msg_pmdl ** pmdl)
736{
737 *pmdl = fd_msg_pmdl_get_inbuf(buffer, expected_len);
738 fd_list_init(&(*pmdl)->sentinel, NULL);
739 CHECK_POSIX(pthread_mutex_init(&(*pmdl)->lock, NULL) );
740 return 0;
741}
742
743static uint8_t * fd_cnx_alloc_msg_buffer(size_t expected_len, struct fd_msg_pmdl ** pmdl)
744{
745 uint8_t * ret = NULL;
746
747 CHECK_MALLOC_DO( ret = malloc( fd_msg_pmdl_sizewithoverhead(expected_len) ), return NULL );
748 CHECK_FCT_DO( fd_cnx_init_msg_buffer(ret, expected_len, pmdl), {free(ret); return NULL;} );
749 return ret;
750}
751
752#ifndef DISABLE_SCTP /* WE use this function only in SCTP code */
753static uint8_t * fd_cnx_realloc_msg_buffer(uint8_t * buffer, size_t expected_len, struct fd_msg_pmdl ** pmdl)
754{
755 uint8_t * ret = NULL;
756
757 CHECK_MALLOC_DO( ret = realloc( buffer, fd_msg_pmdl_sizewithoverhead(expected_len) ), return NULL );
758 CHECK_FCT_DO( fd_cnx_init_msg_buffer(ret, expected_len, pmdl), {free(ret); return NULL;} );
759 return ret;
760}
761#endif /* DISABLE_SCTP */
762
763static void free_rcvdata(void * arg)
764{
765 struct fd_cnx_rcvdata * data = arg;
766 struct fd_msg_pmdl * pmdl = fd_msg_pmdl_get_inbuf(data->buffer, data->length);
767 (void) pthread_mutex_destroy(&pmdl->lock);
768 free(data->buffer);
769}
770
771/* Receiver thread (TCP & noTLS) : incoming message is directly saved into the target queue */
772static void * rcvthr_notls_tcp(void * arg)
773{
774 struct cnxctx * conn = arg;
775
776 TRACE_ENTRY("%p", arg);
777 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out);
778
779 /* Set the thread name */
780 {
781 char buf[48];
782 snprintf(buf, sizeof(buf), "Receiver (%d) TCP/noTLS)", conn->cc_socket);
783 fd_log_threadname ( buf );
784 }
785
786 ASSERT( conn->cc_proto == IPPROTO_TCP );
787 ASSERT( ! fd_cnx_teststate(conn, CC_STATUS_TLS ) );
788 ASSERT( fd_cnx_target_queue(conn) );
789
790 /* Receive from a TCP connection: we have to rebuild the message boundaries */
791 do {
792 uint8_t header[4];
793 struct fd_cnx_rcvdata rcv_data;
794 struct fd_msg_pmdl *pmdl=NULL;
795 ssize_t ret = 0;
796 size_t received = 0;
797
798 do {
799 ret = fd_cnx_s_recv(conn, &header[received], sizeof(header) - received);
800 if (ret <= 0) {
801 goto out; /* Stop the thread, the event was already sent */
802 }
803
804 received += ret;
805
806 if (header[0] != DIAMETER_VERSION)
807 break; /* No need to wait for 4 bytes in this case */
808 } while (received < sizeof(header));
809
810 rcv_data.length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
811
812 /* Check the received word is a valid begining of a Diameter message */
813 if ((header[0] != DIAMETER_VERSION) /* defined in <libfdproto.h> */
814 || (rcv_data.length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
815 /* The message is suspect */
816 LOG_E( "Received suspect header [ver: %d, size: %zd] from '%s', assuming disconnection", (int)header[0], rcv_data.length, conn->cc_remid);
817 fd_cnx_markerror(conn);
818 goto out; /* Stop the thread, the recipient of the event will cleanup */
819 }
820
821 /* Ok, now we can really receive the data */
822 CHECK_MALLOC_DO( rcv_data.buffer = fd_cnx_alloc_msg_buffer( rcv_data.length, &pmdl ), goto fatal );
823 memcpy(rcv_data.buffer, header, sizeof(header));
824
825 while (received < rcv_data.length) {
826 pthread_cleanup_push(free_rcvdata, &rcv_data); /* In case we are canceled, clean the partialy built buffer */
827 ret = fd_cnx_s_recv(conn, rcv_data.buffer + received, rcv_data.length - received);
828 pthread_cleanup_pop(0);
829
830 if (ret <= 0) {
831 free_rcvdata(&rcv_data);
832 goto out;
833 }
834 received += ret;
835 }
836
837 fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl);
838
839 /* We have received a complete message, pass it to the daemon */
840 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer),
841 {
842 free_rcvdata(&rcv_data);
843 goto fatal;
844 } );
845
846 } while (conn->cc_loop);
847
848out:
849 TRACE_DEBUG(FULL, "Thread terminated");
850 return NULL;
851
852fatal:
853 /* An unrecoverable error occurred, stop the daemon */
854 CHECK_FCT_DO(fd_core_shutdown(), );
855 goto out;
856}
857
858#ifndef DISABLE_SCTP
859/* Receiver thread (SCTP & noTLS) : incoming message is directly saved into cc_incoming, no need to care for the stream ID */
860static void * rcvthr_notls_sctp(void * arg)
861{
862 struct cnxctx * conn = arg;
863 struct fd_cnx_rcvdata rcv_data;
864 int event;
865
866 TRACE_ENTRY("%p", arg);
867 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto fatal);
868
869 /* Set the thread name */
870 {
871 char buf[48];
872 snprintf(buf, sizeof(buf), "Receiver (%d) SCTP/noTLS)", conn->cc_socket);
873 fd_log_threadname ( buf );
874 }
875
876 ASSERT( conn->cc_proto == IPPROTO_SCTP );
877 ASSERT( ! fd_cnx_teststate(conn, CC_STATUS_TLS ) );
878 ASSERT( fd_cnx_target_queue(conn) );
879
880 do {
881 struct fd_msg_pmdl *pmdl=NULL;
882 CHECK_FCT_DO( fd_sctp_recvmeta(conn, NULL, &rcv_data.buffer, &rcv_data.length, &event), goto fatal );
883 if (event == FDEVP_CNX_ERROR) {
884 fd_cnx_markerror(conn);
885 goto out;
886 }
887
888 if (event == FDEVP_CNX_SHUTDOWN) {
889 /* Just ignore the notification for now, we will get another error later anyway */
890 continue;
891 }
892
893 if (event == FDEVP_CNX_MSG_RECV) {
894 CHECK_MALLOC_DO( rcv_data.buffer = fd_cnx_realloc_msg_buffer(rcv_data.buffer, rcv_data.length, &pmdl), goto fatal );
895 fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl);
896 }
897 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, rcv_data.length, rcv_data.buffer), goto fatal );
898
899 } while (conn->cc_loop || (event != FDEVP_CNX_MSG_RECV));
900
901out:
902 TRACE_DEBUG(FULL, "Thread terminated");
903 return NULL;
904
905fatal:
906 /* An unrecoverable error occurred, stop the daemon */
907 CHECK_FCT_DO(fd_core_shutdown(), );
908 goto out;
909}
910#endif /* DISABLE_SCTP */
911
912/* Start receving messages in clear (no TLS) on the connection */
913int fd_cnx_start_clear(struct cnxctx * conn, int loop)
914{
915 TRACE_ENTRY("%p %i", conn, loop);
916
917 CHECK_PARAMS( conn && fd_cnx_target_queue(conn) && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && (!conn->cc_loop));
918
919 /* Release resources in case of a previous call was already made */
920 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */);
921
922 /* Save the loop request */
923 conn->cc_loop = loop;
924
925 switch (conn->cc_proto) {
926 case IPPROTO_TCP:
927 /* Start the tcp_notls thread */
928 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_tcp, conn ) );
929 break;
930#ifndef DISABLE_SCTP
931 case IPPROTO_SCTP:
932 /* Start the tcp_notls thread */
933 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_sctp, conn ) );
934 break;
935#endif /* DISABLE_SCTP */
936 default:
937 TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto);
938 ASSERT(0);
939 return ENOTSUP;
940 }
941
942 return 0;
943}
944
945
946
947
948/* Returns 0 on error, received data size otherwise (always >= 0). This is not used for DTLS-protected associations. */
949static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
950{
951 ssize_t ret;
952again:
953 CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz),
954 {
955 switch (ret) {
956 case GNUTLS_E_REHANDSHAKE:
957 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) {
958 CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
959 {
960 if (TRACE_BOOL(INFO)) {
961 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
962 }
963 goto end;
964 } );
965 }
966
967 case GNUTLS_E_AGAIN:
968 case GNUTLS_E_INTERRUPTED:
969 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING))
970 goto again;
971 TRACE_DEBUG(FULL, "Connection is closing, so abord gnutls_record_recv now.");
972 break;
973
974 case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
975 /* The connection is closed */
976 TRACE_DEBUG(FULL, "Got 0 size while reading the socket, probably connection closed...");
977 break;
978
979 default:
980 if (gnutls_error_is_fatal (ret) == 0) {
981 LOG_N("Ignoring non-fatal GNU TLS error: %s", gnutls_strerror (ret));
982 goto again;
983 }
984 LOG_E("Fatal GNUTLS error: %s", gnutls_strerror (ret));
985 }
986 } );
987
988 if (ret == 0)
989 CHECK_GNUTLS_DO( gnutls_bye(session, GNUTLS_SHUT_RDWR), );
990
991end:
992 if (ret <= 0)
993 fd_cnx_markerror(conn);
994 return ret;
995}
996
997/* Wrapper around gnutls_record_send to handle some error codes. This is also used for DTLS-protected associations */
998static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
999{
1000 ssize_t ret;
1001 struct timespec ts, now;
1002 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), return -1 );
1003again:
1004 CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz),
1005 {
1006 pthread_testcancel();
1007 switch (ret) {
1008 case GNUTLS_E_REHANDSHAKE:
1009 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) {
1010 CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
1011 {
1012 if (TRACE_BOOL(INFO)) {
1013 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
1014 }
1015 goto end;
1016 } );
1017 }
1018
1019 case GNUTLS_E_AGAIN:
1020 case GNUTLS_E_INTERRUPTED:
1021 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), return -1 );
1022 if ( ((now.tv_sec - ts.tv_sec) * 1000 + ((now.tv_nsec - ts.tv_nsec) / 1000000L)) > MAX_HOTL_BLOCKING_TIME) {
1023 LOG_D("Unable to send any data for %dms, closing the connection", MAX_HOTL_BLOCKING_TIME);
1024 } else if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING )) {
1025 goto again;
1026 }
1027 break;
1028
1029 default:
1030 if (gnutls_error_is_fatal (ret) == 0) {
1031 LOG_N("Ignoring non-fatal GNU TLS error: %s", gnutls_strerror (ret));
1032 goto again;
1033 }
1034 LOG_E("Fatal GNUTLS error: %s", gnutls_strerror (ret));
1035 }
1036 } );
1037end:
1038 if (ret <= 0)
1039 fd_cnx_markerror(conn);
1040
1041 return ret;
1042}
1043
1044
1045/* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */
1046/* For the case of DTLS, since we are not using SCTP_UNORDERED, the messages over a single stream are ordered.
1047 Furthermore, as long as messages are shorter than the MTU [2^14 = 16384 bytes], they are delivered in a single
1048 record, as far as I understand.
1049 For larger messages, however, it is possible that pieces of messages coming from different streams can get interleaved.
1050 As a result, we do not use the following function for DTLS reception, because we use the sequence number to rebuild the
1051 messages. */
1052int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session)
1053{
1054 /* No guarantee that GnuTLS preserves the message boundaries, so we re-build it as in TCP. */
1055 do {
1056 uint8_t header[4];
1057 struct fd_cnx_rcvdata rcv_data;
1058 struct fd_msg_pmdl *pmdl=NULL;
1059 ssize_t ret = 0;
1060 size_t received = 0;
1061
1062 do {
1063 ret = fd_tls_recv_handle_error(conn, session, &header[received], sizeof(header) - received);
1064 if (ret <= 0) {
1065 /* The connection is closed */
1066 goto out;
1067 }
1068 received += ret;
1069 } while (received < sizeof(header));
1070
1071 rcv_data.length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
1072
1073 /* Check the received word is a valid beginning of a Diameter message */
1074 if ((header[0] != DIAMETER_VERSION) /* defined in <libfreeDiameter.h> */
1075 || (rcv_data.length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
1076 /* The message is suspect */
1077 LOG_E( "Received suspect header [ver: %d, size: %zd] from '%s', assume disconnection", (int)header[0], rcv_data.length, conn->cc_remid);
1078 fd_cnx_markerror(conn);
1079 goto out;
1080 }
1081
1082 /* Ok, now we can really receive the data */
1083 CHECK_MALLOC( rcv_data.buffer = fd_cnx_alloc_msg_buffer( rcv_data.length, &pmdl ) );
1084 memcpy(rcv_data.buffer, header, sizeof(header));
1085
1086 while (received < rcv_data.length) {
1087 pthread_cleanup_push(free_rcvdata, &rcv_data); /* In case we are canceled, clean the partialy built buffer */
1088 ret = fd_tls_recv_handle_error(conn, session, rcv_data.buffer + received, rcv_data.length - received);
1089 pthread_cleanup_pop(0);
1090
1091 if (ret <= 0) {
1092 free_rcvdata(&rcv_data);
1093 goto out;
1094 }
1095 received += ret;
1096 }
1097
1098 fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl);
1099
1100 /* We have received a complete message, pass it to the daemon */
1101 CHECK_FCT_DO( ret = fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer),
1102 {
1103 free_rcvdata(&rcv_data);
1104 CHECK_FCT_DO(fd_core_shutdown(), );
1105 return ret;
1106 } );
1107
1108 } while (1);
1109
1110out:
1111 return ENOTCONN;
1112}
1113
1114/* Receiver thread (TLS & 1 stream SCTP or TCP) */
1115static void * rcvthr_tls_single(void * arg)
1116{
1117 struct cnxctx * conn = arg;
1118
1119 TRACE_ENTRY("%p", arg);
1120 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), return NULL );
1121
1122 /* Set the thread name */
1123 {
1124 char buf[48];
1125 snprintf(buf, sizeof(buf), "Receiver (%d) TLS/single stream", conn->cc_socket);
1126 fd_log_threadname ( buf );
1127 }
1128
1129 ASSERT( fd_cnx_teststate(conn, CC_STATUS_TLS) );
1130 ASSERT( fd_cnx_target_queue(conn) );
1131
1132 /* The next function only returns when there is an error on the socket */
1133 CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */);
1134
1135 TRACE_DEBUG(FULL, "Thread terminated");
1136 return NULL;
1137}
1138
1139/* Prepare a gnutls session object for handshake */
1140int fd_tls_prepare(gnutls_session_t * session, int mode, int dtls, char * priority, void * alt_creds)
1141{
1142 if (dtls) {
1143 LOG_E("DTLS sessions not yet supported");
1144 return ENOTSUP;
1145 }
1146
1147 /* Create the session context */
1148 CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM );
1149
1150 /* Set the algorithm suite */
1151 if (priority) {
1152 const char * errorpos;
1153 CHECK_GNUTLS_DO( gnutls_priority_set_direct( *session, priority, &errorpos ),
1154 { TRACE_DEBUG(INFO, "Error in priority string '%s' at position: '%s'", priority, errorpos); return EINVAL; } );
1155 } else {
1156 CHECK_GNUTLS_DO( gnutls_priority_set( *session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL );
1157 }
1158
1159 /* Set the credentials of this side of the connection */
1160 CHECK_GNUTLS_DO( gnutls_credentials_set (*session, GNUTLS_CRD_CERTIFICATE, alt_creds ?: fd_g_config->cnf_sec_data.credentials), return EINVAL );
1161
1162 /* Request the remote credentials as well */
1163 if (mode == GNUTLS_SERVER) {
1164 gnutls_certificate_server_set_request (*session, GNUTLS_CERT_REQUIRE);
1165 }
1166
1167 return 0;
1168}
1169
1170#ifndef GNUTLS_VERSION_300
1171
1172/* Verify remote credentials after successful handshake (return 0 if OK, EINVAL otherwise) */
1173int fd_tls_verify_credentials(gnutls_session_t session, struct cnxctx * conn, int verbose)
1174{
1175 int i, ret = 0;
1176 unsigned int gtret;
1177 const gnutls_datum_t *cert_list;
1178 unsigned int cert_list_size;
1179 gnutls_x509_crt_t cert;
1180 time_t now;
1181
1182 TRACE_ENTRY("%p %d", conn, verbose);
1183 CHECK_PARAMS(conn);
1184
1185 /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */
1186 #ifdef DEBUG
1187 if (verbose) {
1188 const char *tmp;
1189 gnutls_kx_algorithm_t kx;
1190 gnutls_credentials_type_t cred;
1191
1192 LOG_D("TLS Session information for connection '%s':", conn->cc_id);
1193
1194 /* print the key exchange's algorithm name */
1195 GNUTLS_TRACE( kx = gnutls_kx_get (session) );
1196 GNUTLS_TRACE( tmp = gnutls_kx_get_name (kx) );
1197 LOG_D("\t - Key Exchange: %s", tmp);
1198
1199 /* Check the authentication type used and switch
1200 * to the appropriate. */
1201 GNUTLS_TRACE( cred = gnutls_auth_get_type (session) );
1202 switch (cred)
1203 {
1204 case GNUTLS_CRD_IA:
1205 LOG_D("\t - TLS/IA session");
1206 break;
1207
1208 case GNUTLS_CRD_PSK:
1209 /* This returns NULL in server side. */
1210 if (gnutls_psk_client_get_hint (session) != NULL)
1211 LOG_D("\t - PSK authentication. PSK hint '%s'",
1212 gnutls_psk_client_get_hint (session));
1213 /* This returns NULL in client side. */
1214 if (gnutls_psk_server_get_username (session) != NULL)
1215 LOG_D("\t - PSK authentication. Connected as '%s'",
1216 gnutls_psk_server_get_username (session));
1217 break;
1218
1219 case GNUTLS_CRD_ANON: /* anonymous authentication */
1220 LOG_D("\t - Anonymous DH using prime of %d bits",
1221 gnutls_dh_get_prime_bits (session));
1222 break;
1223
1224 case GNUTLS_CRD_CERTIFICATE: /* certificate authentication */
1225 /* Check if we have been using ephemeral Diffie-Hellman. */
1226 if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) {
1227 LOG_D("\t - Ephemeral DH using prime of %d bits",
1228 gnutls_dh_get_prime_bits (session));
1229 }
1230 break;
1231#ifdef ENABLE_SRP
1232 case GNUTLS_CRD_SRP:
1233 LOG_D("\t - SRP session with username %s",
1234 gnutls_srp_server_get_username (session));
1235 break;
1236#endif /* ENABLE_SRP */
1237
1238 default:
1239 fd_log_debug("\t - Different type of credentials for the session (%d).", cred);
1240 break;
1241
1242 }
1243
1244 /* print the protocol's name (ie TLS 1.0) */
1245 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
1246 LOG_D("\t - Protocol: %s", tmp);
1247
1248 /* print the certificate type of the peer. ie X.509 */
1249 tmp = gnutls_certificate_type_get_name (gnutls_certificate_type_get (session));
1250 LOG_D("\t - Certificate Type: %s", tmp);
1251
1252 /* print the compression algorithm (if any) */
1253 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
1254 LOG_D("\t - Compression: %s", tmp);
1255
1256 /* print the name of the cipher used. ie 3DES. */
1257 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
1258 LOG_D("\t - Cipher: %s", tmp);
1259
1260 /* Print the MAC algorithms name. ie SHA1 */
1261 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
1262 LOG_D("\t - MAC: %s", tmp);
1263 }
1264 #endif /* DEBUG */
1265
1266 /* First, use built-in verification */
1267 CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (session, &gtret), return EINVAL );
1268 if (gtret) {
1269 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id);
1270 if (gtret & GNUTLS_CERT_INVALID)
1271 LOG_E(" - The certificate is not trusted (unknown CA? expired?)");
1272 if (gtret & GNUTLS_CERT_REVOKED)
1273 LOG_E(" - The certificate has been revoked.");
1274 if (gtret & GNUTLS_CERT_SIGNER_NOT_FOUND)
1275 LOG_E(" - The certificate hasn't got a known issuer.");
1276 if (gtret & GNUTLS_CERT_SIGNER_NOT_CA)
1277 LOG_E(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.");
1278 if (gtret & GNUTLS_CERT_INSECURE_ALGORITHM)
1279 LOG_E(" - The certificate signature uses a weak algorithm.");
1280 return EINVAL;
1281 }
1282
1283 /* Code from http://www.gnu.org/software/gnutls/manual/gnutls.html#Verifying-peer_0027s-certificate */
1284 if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
1285 LOG_E("TLS: Remote peer did not present a certificate, other mechanisms are not supported yet. socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id);
1286 return EINVAL;
1287 }
1288
1289 GNUTLS_TRACE( cert_list = gnutls_certificate_get_peers (session, &cert_list_size) );
1290 if (cert_list == NULL)
1291 return EINVAL;
1292
1293 now = time(NULL);
1294
1295 #ifdef DEBUG
1296 char serial[40];
1297 char dn[128];
1298 size_t size;
1299 unsigned int algo, bits;
1300 time_t expiration_time, activation_time;
1301
1302 LOG_D("TLS Certificate information for connection '%s' (%d certs provided):", conn->cc_id, cert_list_size);
1303 for (i = 0; i < cert_list_size; i++)
1304 {
1305
1306 CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return EINVAL);
1307 CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER), return EINVAL);
1308
1309 LOG_A(" Certificate %d info:", i);
1310
1311 GNUTLS_TRACE( expiration_time = gnutls_x509_crt_get_expiration_time (cert) );
1312 GNUTLS_TRACE( activation_time = gnutls_x509_crt_get_activation_time (cert) );
1313
1314 LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate is valid since: %.24s", ctime (&activation_time));
1315 LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate expires: %.24s", ctime (&expiration_time));
1316
1317 /* Print the serial number of the certificate. */
1318 size = sizeof (serial);
1319 gnutls_x509_crt_get_serial (cert, serial, &size);
1320
1321 {
1322 int j;
1323 char buf[1024];
1324 snprintf(buf, sizeof(buf), "\t - Certificate serial number: ");
1325 for (j = 0; j < size; j++) {
1326 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%02hhx", serial[j]);
1327 }
1328 LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "%s", buf);
1329 }
1330
1331 /* Extract some of the public key algorithm's parameters */
1332 GNUTLS_TRACE( algo = gnutls_x509_crt_get_pk_algorithm (cert, &bits) );
1333 LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate public key: %s",
1334 gnutls_pk_algorithm_get_name (algo));
1335
1336 /* Print the version of the X.509 certificate. */
1337 LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate version: #%d",
1338 gnutls_x509_crt_get_version (cert));
1339
1340 size = sizeof (dn);
1341 GNUTLS_TRACE( gnutls_x509_crt_get_dn (cert, dn, &size) );
1342 LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - DN: %s", dn);
1343
1344 size = sizeof (dn);
1345 GNUTLS_TRACE( gnutls_x509_crt_get_issuer_dn (cert, dn, &size) );
1346 LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Issuer's DN: %s", dn);
1347
1348 GNUTLS_TRACE( gnutls_x509_crt_deinit (cert) );
1349 }
1350 #endif /* DEBUG */
1351
1352 /* Check validity of all the certificates */
1353 for (i = 0; i < cert_list_size; i++)
1354 {
1355 time_t deadline;
1356
1357 CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return EINVAL);
1358 CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER), return EINVAL);
1359
1360 GNUTLS_TRACE( deadline = gnutls_x509_crt_get_expiration_time(cert) );
1361 if ((deadline != (time_t)-1) && (deadline < now)) {
1362 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id);
1363 LOG_E(" - The certificate %d in the chain is expired", i);
1364 ret = EINVAL;
1365 }
1366
1367 GNUTLS_TRACE( deadline = gnutls_x509_crt_get_activation_time(cert) );
1368 if ((deadline != (time_t)-1) && (deadline > now)) {
1369 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id);
1370 LOG_E(" - The certificate %d in the chain is not yet activated", i);
1371 ret = EINVAL;
1372 }
1373
1374 if ((i == 0) && (conn->cc_tls_para.cn)) {
1375 if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) {
1376 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id);
1377 LOG_E(" - The certificate hostname does not match '%s'", conn->cc_tls_para.cn);
1378 ret = EINVAL;
1379 }
1380 }
1381
1382 GNUTLS_TRACE( gnutls_x509_crt_deinit (cert) );
1383 }
1384
1385 return ret;
1386}
1387
1388#else /* GNUTLS_VERSION_300 */
1389
1390/* Verify remote credentials DURING handshake (return gnutls status) */
1391int fd_tls_verify_credentials_2(gnutls_session_t session)
1392{
1393 /* inspired from gnutls 3.x guidelines */
1394 unsigned int status;
1395 const gnutls_datum_t *cert_list = NULL;
1396 unsigned int cert_list_size;
1397 gnutls_x509_crt_t cert;
1398 struct cnxctx * conn;
1399 int hostname_verified = 0;
1400
1401 TRACE_ENTRY("%p", session);
1402
1403 /* get the associated connection */
1404 conn = gnutls_session_get_ptr (session);
1405
1406 /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */
1407#ifdef DEBUG
1408 const char *tmp;
1409 gnutls_credentials_type_t cred;
1410 gnutls_kx_algorithm_t kx;
1411 int dhe, ecdh;
1412
1413 dhe = ecdh = 0;
1414
1415 LOG_A("TLS Session information for connection '%s':", conn->cc_id);
1416
1417 /* print the key exchange's algorithm name
1418 */
1419 GNUTLS_TRACE( kx = gnutls_kx_get (session) );
1420 GNUTLS_TRACE( tmp = gnutls_kx_get_name (kx) );
1421 LOG_D("\t- Key Exchange: %s", tmp);
1422
1423 /* Check the authentication type used and switch
1424 * to the appropriate.
1425 */
1426 GNUTLS_TRACE( cred = gnutls_auth_get_type (session) );
1427 switch (cred)
1428 {
1429 case GNUTLS_CRD_IA:
1430 LOG_D("\t - TLS/IA session");
1431 break;
1432
1433
1434 #ifdef ENABLE_SRP
1435 case GNUTLS_CRD_SRP:
1436 LOG_D("\t - SRP session with username %s",
1437 gnutls_srp_server_get_username (session));
1438 break;
1439 #endif
1440
1441 case GNUTLS_CRD_PSK:
1442 /* This returns NULL in server side.
1443 */
1444 if (gnutls_psk_client_get_hint (session) != NULL)
1445 LOG_D("\t - PSK authentication. PSK hint '%s'",
1446 gnutls_psk_client_get_hint (session));
1447 /* This returns NULL in client side.
1448 */
1449 if (gnutls_psk_server_get_username (session) != NULL)
1450 LOG_D("\t - PSK authentication. Connected as '%s'",
1451 gnutls_psk_server_get_username (session));
1452
1453 if (kx == GNUTLS_KX_ECDHE_PSK)
1454 ecdh = 1;
1455 else if (kx == GNUTLS_KX_DHE_PSK)
1456 dhe = 1;
1457 break;
1458
1459 case GNUTLS_CRD_ANON: /* anonymous authentication */
1460 LOG_D("\t - Anonymous DH using prime of %d bits",
1461 gnutls_dh_get_prime_bits (session));
1462 if (kx == GNUTLS_KX_ANON_ECDH)
1463 ecdh = 1;
1464 else if (kx == GNUTLS_KX_ANON_DH)
1465 dhe = 1;
1466 break;
1467
1468 case GNUTLS_CRD_CERTIFICATE: /* certificate authentication */
1469
1470 /* Check if we have been using ephemeral Diffie-Hellman.
1471 */
1472 if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS)
1473 dhe = 1;
1474 else if (kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA)
1475 ecdh = 1;
1476
1477 /* Now print some info on the remote certificate */
1478 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509) {
1479 gnutls_datum_t cinfo;
1480
1481 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
1482
1483 LOG_D("\t Peer provided %d certificates.", cert_list_size);
1484
1485 if (cert_list_size > 0)
1486 {
1487 int ret;
1488
1489 /* we only print information about the first certificate.
1490 */
1491 gnutls_x509_crt_init (&cert);
1492
1493 gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER);
1494
1495 LOG_A("\t Certificate info:");
1496
1497 /* This is the preferred way of printing short information about
1498 a certificate. */
1499
1500 ret = gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_ONELINE, &cinfo);
1501 if (ret == 0)
1502 {
1503 LOG_D("\t\t%s", cinfo.data);
1504 gnutls_free (cinfo.data);
1505 }
1506
1507 if (conn->cc_tls_para.cn) {
1508 if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) {
1509 LOG_E("\tTLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id);
1510 LOG_E("\t - The certificate hostname does not match '%s'", conn->cc_tls_para.cn);
1511 gnutls_x509_crt_deinit (cert);
1512 return GNUTLS_E_CERTIFICATE_ERROR;
1513 }
1514
1515 }
1516
1517 hostname_verified = 1;
1518
1519 gnutls_x509_crt_deinit (cert);
1520
1521 }
1522 }
1523 break;
1524
1525 default:
1526 LOG_E("\t - unknown session type (%d)", cred);
1527
1528 } /* switch */
1529
1530 if (ecdh != 0)
1531 LOG_D("\t - Ephemeral ECDH using curve %s",
1532 gnutls_ecc_curve_get_name (gnutls_ecc_curve_get (session)));
1533 else if (dhe != 0)
1534 LOG_D("\t - Ephemeral DH using prime of %d bits",
1535 gnutls_dh_get_prime_bits (session));
1536
1537 /* print the protocol's name (ie TLS 1.0)
1538 */
1539 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
1540 LOG_D("\t - Protocol: %s", tmp);
1541
1542 /* print the certificate type of the peer.
1543 * ie X.509
1544 */
1545 tmp = gnutls_certificate_type_get_name (gnutls_certificate_type_get (session));
1546 LOG_D("\t - Certificate Type: %s", tmp);
1547
1548 /* print the compression algorithm (if any)
1549 */
1550 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
1551 LOG_D("\t - Compression: %s", tmp);
1552
1553 /* print the name of the cipher used.
1554 * ie 3DES.
1555 */
1556 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
1557 LOG_D("\t - Cipher: %s", tmp);
1558
1559 /* Print the MAC algorithms name.
1560 * ie SHA1
1561 */
1562 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
1563 LOG_D("\t - MAC: %s", tmp);
1564
1565#endif /* DEBUG */
1566
1567 /* This verification function uses the trusted CAs in the credentials
1568 * structure. So you must have installed one or more CA certificates.
1569 */
1570 CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (session, &status), return GNUTLS_E_CERTIFICATE_ERROR );
1571 if (status & GNUTLS_CERT_INVALID) {
1572 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id);
1573 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
1574 LOG_E(" - The certificate hasn't got a known issuer.");
1575
1576 if (status & GNUTLS_CERT_REVOKED)
1577 LOG_E(" - The certificate has been revoked.");
1578
1579 if (status & GNUTLS_CERT_EXPIRED)
1580 LOG_E(" - The certificate has expired.");
1581
1582 if (status & GNUTLS_CERT_NOT_ACTIVATED)
1583 LOG_E(" - The certificate is not yet activated.");
1584 }
1585 if (status & GNUTLS_CERT_INVALID)
1586 {
1587 return GNUTLS_E_CERTIFICATE_ERROR;
1588 }
1589
1590 /* Up to here the process is the same for X.509 certificates and
1591 * OpenPGP keys. From now on X.509 certificates are assumed. This can
1592 * be easily extended to work with openpgp keys as well.
1593 */
1594 if ((!hostname_verified) && (conn->cc_tls_para.cn)) {
1595 if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
1596 LOG_E("TLS: Remote credentials are not x509, rejected on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id);
1597 return GNUTLS_E_CERTIFICATE_ERROR;
1598 }
1599
1600 CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return GNUTLS_E_CERTIFICATE_ERROR );
1601
1602 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
1603 CHECK_PARAMS_DO( cert_list, return GNUTLS_E_CERTIFICATE_ERROR );
1604
1605 CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER), return GNUTLS_E_CERTIFICATE_ERROR );
1606
1607 if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) {
1608 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id);
1609 LOG_E(" - The certificate hostname does not match '%s'", conn->cc_tls_para.cn);
1610 gnutls_x509_crt_deinit (cert);
1611 return GNUTLS_E_CERTIFICATE_ERROR;
1612 }
1613
1614 gnutls_x509_crt_deinit (cert);
1615 }
1616
1617 /* notify gnutls to continue handshake normally */
1618 return 0;
1619}
1620
1621#endif /* GNUTLS_VERSION_300 */
1622
1623static int fd_cnx_may_dtls(struct cnxctx * conn) {
1624#ifndef DISABLE_SCTP
1625 if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_tls_para.algo == ALGO_HANDSHAKE_DEFAULT))
1626 return 1;
1627#endif /* DISABLE_SCTP */
1628 return 0;
1629}
1630
1631#ifndef DISABLE_SCTP
1632static int fd_cnx_uses_dtls(struct cnxctx * conn) {
1633 return fd_cnx_may_dtls(conn) && (fd_cnx_teststate(conn, CC_STATUS_TLS));
1634}
1635#endif /* DISABLE_SCTP */
1636
1637/* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */
1638int fd_cnx_handshake(struct cnxctx * conn, int mode, int algo, char * priority, void * alt_creds)
1639{
1640 int dtls = 0;
1641
1642 TRACE_ENTRY( "%p %d %d %p %p", conn, mode, algo, priority, alt_creds);
1643 CHECK_PARAMS( conn && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );
1644
1645 /* Save the mode */
1646 conn->cc_tls_para.mode = mode;
1647 conn->cc_tls_para.algo = algo;
1648
1649 /* Cancel receiving thread if any -- it should already be terminated anyway, we just release the resources */
1650 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */);
1651
1652 /* Once TLS handshake is done, we don't stop after the first message */
1653 conn->cc_loop = 1;
1654
1655 dtls = fd_cnx_may_dtls(conn);
1656
1657 /* Prepare the master session credentials and priority */
1658 CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, dtls, priority, alt_creds) );
1659
1660 /* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */
1661 if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) {
1662#ifdef DISABLE_SCTP
1663 ASSERT(0);
1664 CHECK_FCT( ENOTSUP );
1665#else /* DISABLE_SCTP */
1666 /* Initialize the wrapper, start the demux thread */
1667 CHECK_FCT( fd_sctp3436_init(conn) );
1668#endif /* DISABLE_SCTP */
1669 } else {
1670 /* Set the transport pointer passed to push & pull callbacks */
1671 GNUTLS_TRACE( gnutls_transport_set_ptr( conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn ) );
1672
1673 /* Set the push and pull callbacks */
1674 if (!dtls) {
1675 #ifdef GNUTLS_VERSION_300
1676 GNUTLS_TRACE( gnutls_transport_set_pull_timeout_function( conn->cc_tls_para.session, (void *)fd_cnx_s_select ) );
1677 #endif /* GNUTLS_VERSION_300 */
1678 GNUTLS_TRACE( gnutls_transport_set_pull_function(conn->cc_tls_para.session, (void *)fd_cnx_s_recv) );
1679 #ifndef GNUTLS_VERSION_212
1680 GNUTLS_TRACE( gnutls_transport_set_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_send) );
1681 #else /* GNUTLS_VERSION_212 */
1682 GNUTLS_TRACE( gnutls_transport_set_vec_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_sendv) );
1683 #endif /* GNUTLS_VERSION_212 */
1684 } else {
1685 TODO("DTLS push/pull functions");
1686 return ENOTSUP;
1687 }
1688 }
1689
1690 /* additional initialization for gnutls 3.x */
1691 #ifdef GNUTLS_VERSION_300
1692 /* the verify function has already been set in the global initialization in config.c */
1693
1694 /* fd_tls_verify_credentials_2 uses the connection */
1695 gnutls_session_set_ptr (conn->cc_tls_para.session, (void *) conn);
1696
1697 if ((conn->cc_tls_para.cn != NULL) && (mode == GNUTLS_CLIENT)) {
1698 /* this might allow virtual hosting on the remote peer */
1699 CHECK_GNUTLS_DO( gnutls_server_name_set (conn->cc_tls_para.session, GNUTLS_NAME_DNS, conn->cc_tls_para.cn, strlen(conn->cc_tls_para.cn)), /* ignore failure */);
1700 }
1701
1702 #endif /* GNUTLS_VERSION_300 */
1703
1704 #ifdef GNUTLS_VERSION_310
1705 GNUTLS_TRACE( gnutls_handshake_set_timeout( conn->cc_tls_para.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
1706 #endif /* GNUTLS_VERSION_310 */
1707
1708 /* Mark the connection as protected from here, so that the gnutls credentials will be freed */
1709 fd_cnx_addstate(conn, CC_STATUS_TLS);
1710
1711 /* Handshake master session */
1712 {
1713 int ret;
1714
1715 CHECK_GNUTLS_DO( ret = gnutls_handshake(conn->cc_tls_para.session),
1716 {
1717 if (TRACE_BOOL(INFO)) {
1718 fd_log_debug("TLS Handshake failed on socket %d (%s) : %s", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
1719 }
1720 fd_cnx_markerror(conn);
1721 return EINVAL;
1722 } );
1723
1724 #ifndef GNUTLS_VERSION_300
1725 /* Now verify the remote credentials are valid -- only simple tests here */
1726 CHECK_FCT_DO( fd_tls_verify_credentials(conn->cc_tls_para.session, conn, 1),
1727 {
1728 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), );
1729 fd_cnx_markerror(conn);
1730 return EINVAL;
1731 });
1732 #endif /* GNUTLS_VERSION_300 */
1733 }
1734
1735 /* Multi-stream TLS: handshake other streams as well */
1736 if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) {
1737#ifndef DISABLE_SCTP
1738 /* Start reading the messages from the master session. That way, if the remote peer closed, we are not stuck inside handshake */
1739 CHECK_FCT(fd_sctp3436_startthreads(conn, 0));
1740
1741 /* Resume all additional sessions from the master one. */
1742 CHECK_FCT(fd_sctp3436_handshake_others(conn, priority, alt_creds));
1743
1744 /* Start decrypting the messages from all threads and queuing them in target queue */
1745 CHECK_FCT(fd_sctp3436_startthreads(conn, 1));
1746#endif /* DISABLE_SCTP */
1747 } else {
1748 /* Start decrypting the data */
1749 if (!dtls) {
1750 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_tls_single, conn ) );
1751 } else {
1752 TODO("Signal the dtls_push function that multiple streams can be used from this point.");
1753 TODO("Create DTLS rcvthr (must reassembly based on seq numbers & stream id ?)");
1754 return ENOTSUP;
1755 }
1756 }
1757
1758 return 0;
1759}
1760
1761/* Retrieve TLS credentials of the remote peer, after handshake */
1762int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size)
1763{
1764 TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size);
1765 CHECK_PARAMS( conn && fd_cnx_teststate(conn, CC_STATUS_TLS) && cert_list && cert_list_size );
1766
1767 /* This function only works for X.509 certificates. */
1768 CHECK_PARAMS( gnutls_certificate_type_get (conn->cc_tls_para.session) == GNUTLS_CRT_X509 );
1769
1770 GNUTLS_TRACE( *cert_list = gnutls_certificate_get_peers (conn->cc_tls_para.session, cert_list_size) );
1771 if (*cert_list == NULL) {
1772 TRACE_DEBUG(INFO, "No certificate was provided by remote peer / an error occurred.");
1773 return EINVAL;
1774 }
1775
1776 TRACE_DEBUG( FULL, "Saved certificate chain (%d certificates) in peer structure.", *cert_list_size);
1777
1778 return 0;
1779}
1780
1781/* Receive next message. if timeout is not NULL, wait only until timeout. This function only pulls from a queue, mgr thread is filling that queue aynchrounously. */
1782/* if the altfifo has been set on this conn object, this function must not be called */
1783int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len)
1784{
1785 int ev;
1786 size_t ev_sz;
1787 void * ev_data;
1788
1789 TRACE_ENTRY("%p %p %p %p", conn, timeout, buf, len);
1790 CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len);
1791 CHECK_PARAMS(conn->cc_rcvthr != (pthread_t)NULL);
1792 CHECK_PARAMS(conn->cc_alt == NULL);
1793
1794 /* Now, pull the first event */
1795get_next:
1796 if (timeout) {
1797 CHECK_FCT( fd_event_timedget(conn->cc_incoming, timeout, FDEVP_PSM_TIMEOUT, &ev, &ev_sz, &ev_data) );
1798 } else {
1799 CHECK_FCT( fd_event_get(conn->cc_incoming, &ev, &ev_sz, &ev_data) );
1800 }
1801
1802 switch (ev) {
1803 case FDEVP_CNX_MSG_RECV:
1804 /* We got one */
1805 *len = ev_sz;
1806 *buf = ev_data;
1807 return 0;
1808
1809 case FDEVP_PSM_TIMEOUT:
1810 TRACE_DEBUG(FULL, "Timeout event received");
1811 return ETIMEDOUT;
1812
1813 case FDEVP_CNX_EP_CHANGE:
1814 /* We ignore this event */
1815 goto get_next;
1816
1817 case FDEVP_CNX_ERROR:
1818 TRACE_DEBUG(FULL, "Received ERROR event on the connection");
1819 return ENOTCONN;
1820 }
1821
1822 TRACE_DEBUG(INFO, "Received unexpected event %d (%s)", ev, fd_pev_str(ev));
1823 return EINVAL;
1824}
1825
1826/* Where the events are sent */
1827struct fifo * fd_cnx_target_queue(struct cnxctx * conn)
1828{
1829 struct fifo *q;
1830 CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
1831 q = conn->cc_alt ?: conn->cc_incoming;
1832 CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
1833 return q;
1834}
1835
1836/* Set an alternate FIFO list to send FDEVP_CNX_* events to */
1837int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo)
1838{
1839 int ret;
1840 TRACE_ENTRY( "%p %p", conn, alt_fifo );
1841 CHECK_PARAMS( conn && alt_fifo && conn->cc_incoming );
1842
1843 /* The magic function does it all */
1844 CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
1845 CHECK_FCT_DO( ret = fd_fifo_move( conn->cc_incoming, alt_fifo, &conn->cc_alt ), );
1846 CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
1847
1848 return ret;
1849}
1850
1851/* Send function when no multi-stream is involved, or sending on stream #0 (send() always use stream 0)*/
1852static int send_simple(struct cnxctx * conn, unsigned char * buf, size_t len)
1853{
1854 ssize_t ret;
1855 size_t sent = 0;
1856 TRACE_ENTRY("%p %p %zd", conn, buf, len);
1857 do {
1858 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) {
1859 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent), );
1860 } else {
1861 struct iovec iov;
1862 iov.iov_base = buf + sent;
1863 iov.iov_len = len - sent;
1864 CHECK_SYS_DO( ret = fd_cnx_s_sendv(conn, &iov, 1), );
1865 }
1866 if (ret <= 0)
1867 return ENOTCONN;
1868
1869 sent += ret;
1870 } while ( sent < len );
1871 return 0;
1872}
1873
1874/* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time (on the same conn), so we don't protect. */
1875int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len)
1876{
1877 TRACE_ENTRY("%p %p %zd", conn, buf, len);
1878
1879 CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! fd_cnx_teststate(conn, CC_STATUS_ERROR)) && buf && len);
1880
1881 TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, fd_cnx_teststate(conn, CC_STATUS_TLS) ? "TLS-protected ":"", conn->cc_id);
1882
1883 switch (conn->cc_proto) {
1884 case IPPROTO_TCP:
1885 CHECK_FCT( send_simple(conn, buf, len) );
1886 break;
1887
1888#ifndef DISABLE_SCTP
1889 case IPPROTO_SCTP: {
1890 int dtls = fd_cnx_uses_dtls(conn);
1891 if (!dtls) {
1892 int stream = 0;
1893 if (conn->cc_sctp_para.unordered) {
1894 int limit;
1895 if (fd_cnx_teststate(conn, CC_STATUS_TLS))
1896 limit = conn->cc_sctp_para.pairs;
1897 else
1898 limit = conn->cc_sctp_para.str_out;
1899
1900 if (limit > 1) {
1901 conn->cc_sctp_para.next += 1;
1902 conn->cc_sctp_para.next %= limit;
1903 stream = conn->cc_sctp_para.next;
1904 }
1905 }
1906
1907 if (stream == 0) {
1908 /* We can use default function, it sends over stream #0 */
1909 CHECK_FCT( send_simple(conn, buf, len) );
1910 } else {
1911 if (!fd_cnx_teststate(conn, CC_STATUS_TLS)) {
1912 struct iovec iov;
1913 iov.iov_base = buf;
1914 iov.iov_len = len;
1915
1916 CHECK_SYS_DO( fd_sctp_sendstrv(conn, stream, &iov, 1), { fd_cnx_markerror(conn); return ENOTCONN; } );
1917 } else {
1918 /* push the data to the appropriate session */
1919 ssize_t ret;
1920 size_t sent = 0;
1921 ASSERT(conn->cc_sctp3436_data.array != NULL);
1922 do {
1923 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctp3436_data.array[stream].session, buf + sent, len - sent), );
1924 if (ret <= 0)
1925 return ENOTCONN;
1926
1927 sent += ret;
1928 } while ( sent < len );
1929 }
1930 }
1931 } else {
1932 /* DTLS */
1933 /* Multistream is handled at lower layer in the push/pull function */
1934 CHECK_FCT( send_simple(conn, buf, len) );
1935 }
1936 }
1937 break;
1938#endif /* DISABLE_SCTP */
1939
1940 default:
1941 TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto);
1942 ASSERT(0);
1943 return ENOTSUP; /* or EINVAL... */
1944 }
1945
1946 return 0;
1947}
1948
1949
1950/**************************************/
1951/* Destruction of connection */
1952/**************************************/
1953
1954/* Destroy a conn structure, and shutdown the socket */
1955void fd_cnx_destroy(struct cnxctx * conn)
1956{
1957 TRACE_ENTRY("%p", conn);
1958
1959 CHECK_PARAMS_DO(conn, return);
1960
1961 fd_cnx_addstate(conn, CC_STATUS_CLOSING);
1962
1963 /* Initiate shutdown of the TLS session(s): call gnutls_bye(WR), then read until error */
1964 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) {
1965#ifndef DISABLE_SCTP
1966 int dtls = fd_cnx_uses_dtls(conn);
1967 if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) {
1968 if (! fd_cnx_teststate(conn, CC_STATUS_ERROR )) {
1969 /* Bye on master session */
1970 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) );
1971 }
1972
1973 if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
1974 /* and other stream pairs */
1975 fd_sctp3436_bye(conn);
1976 }
1977
1978 if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
1979 /* Now wait for all decipher threads to terminate */
1980 fd_sctp3436_waitthreadsterm(conn);
1981 } else {
1982 /* Abord the threads, the connection is dead already */
1983 fd_sctp3436_stopthreads(conn);
1984 }
1985
1986 /* Deinit gnutls resources */
1987 fd_sctp3436_gnutls_deinit_others(conn);
1988 if (conn->cc_tls_para.session) {
1989 GNUTLS_TRACE( gnutls_deinit(conn->cc_tls_para.session) );
1990 conn->cc_tls_para.session = NULL;
1991 }
1992
1993 /* Destroy the wrapper (also stops the demux thread) */
1994 fd_sctp3436_destroy(conn);
1995
1996 } else {
1997#endif /* DISABLE_SCTP */
1998 /* We are TLS, but not using the sctp3436 wrapper layer */
1999 if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
2000 /* Master session */
2001 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) );
2002 }
2003
2004 if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
2005 /* In this case, just wait for thread rcvthr_tls_single to terminate */
2006 if (conn->cc_rcvthr != (pthread_t)NULL) {
2007 CHECK_POSIX_DO( pthread_join(conn->cc_rcvthr, NULL), /* continue */ );
2008 conn->cc_rcvthr = (pthread_t)NULL;
2009 }
2010 } else {
2011 /* Cancel the receiver thread in case it did not already terminate */
2012 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );
2013 }
2014
2015 /* Free the resources of the TLS session */
2016 if (conn->cc_tls_para.session) {
2017 GNUTLS_TRACE( gnutls_deinit(conn->cc_tls_para.session) );
2018 conn->cc_tls_para.session = NULL;
2019 }
2020#ifndef DISABLE_SCTP
2021 }
2022#endif /* DISABLE_SCTP */
2023 }
2024
2025 /* Terminate the thread in case it is not done yet -- is there any such case left ?*/
2026 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );
2027
2028 /* Shut the connection down */
2029 if (conn->cc_socket > 0) {
2030 shutdown(conn->cc_socket, SHUT_RDWR);
2031 close(conn->cc_socket);
2032 conn->cc_socket = -1;
2033 }
2034
2035 /* Empty and destroy FIFO list */
2036 if (conn->cc_incoming) {
2037 fd_event_destroy( &conn->cc_incoming, free );
2038 }
2039
2040 /* Free the object */
2041 free(conn);
2042
2043 /* Done! */
2044 return;
2045}