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