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, &gtret), 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