changeset 1540:407e0a889c7e

SCTP ConnectPeer: sctp_bindx() to local endpoints When connecting to an SCTP peer using sctp_connectx() with local addresses configured with ListenOn, bind to the ListenOn addresses using sctp_bindx() so that the SCTP INIT only contains the configured local addresses, matching what is advertised in the CER, and disable SCTP_AUTO_ASCONF. If no local addresses are configured with ListenOn, the previous behaviour of sctp_connectx() and enable SCTP_AUTO_ASCONF is used.
author Luke Mewburn <luke@mewburn.net>
date Fri, 01 May 2020 18:20:33 +1000
parents d25ce064c667
children 3365e95bed57
files include/freeDiameter/libfdcore.h libfdcore/cnxctx.c libfdcore/cnxctx.h libfdcore/config.c libfdcore/fdcore-internal.h libfdcore/p_cnx.c libfdcore/sctp.c tests/testcnx.c tests/testsctp.c
diffstat 9 files changed, 61 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/include/freeDiameter/libfdcore.h	Thu Apr 30 15:24:47 2020 +1000
+++ b/include/freeDiameter/libfdcore.h	Fri May 01 18:20:33 2020 +1000
@@ -151,6 +151,7 @@
 		unsigned no_sctp: 1;	/* disable the use of SCTP */
 		unsigned pr_tcp	: 1;	/* prefer TCP over SCTP */
 		unsigned tls_alg: 1;	/* TLS algorithm for initiated cnx. 0: separate port. 1: inband-security (old) */
+		unsigned no_bind: 1;	/* disable client bind to cnf_endpoints if non configured (bind all) */
 	} 		 cnf_flags;
 	
 	struct {
--- a/libfdcore/cnxctx.c	Thu Apr 30 15:24:47 2020 +1000
+++ b/libfdcore/cnxctx.c	Fri May 01 18:20:33 2020 +1000
@@ -330,8 +330,9 @@
 	return cnx;
 }
 
-/* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx for how they are used) */
-struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list)
+/* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx for how they are used).
+ * If src_list is not NULL and not empty, list of local addresses to connect from via sctp_bindx(). */
+struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list, struct fd_list * src_list)
 {
 #ifdef DISABLE_SCTP
 	TRACE_DEBUG(INFO, "This function should never be called when SCTP is disabled...");
@@ -344,15 +345,32 @@
 	char sa_buf[sSA_DUMP_STRLEN];
 	sSS primary;
 
-	TRACE_ENTRY("%p", list);
+	TRACE_ENTRY("%p %p", list, src_list);
 	CHECK_PARAMS_DO( list && !FD_IS_LIST_EMPTY(list), return NULL );
 
+	/* Log SCTP association source and destination endpoints */
+	{
+		char * buf = NULL;
+		size_t len = 0, offset = 0;
+		CHECK_MALLOC_DO( fd_dump_extend( &buf, &len, &offset, "Connecting SCTP endpoints"), );
+		CHECK_MALLOC_DO( fd_dump_extend( &buf, &len, &offset, " source: "), );
+		if (src_list && !FD_IS_LIST_EMPTY(src_list)) {
+			CHECK_MALLOC_DO( fd_ep_dump( &buf, &len, &offset, 0, 0, src_list ), );
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( &buf, &len, &offset, "(ANY)"), );
+		}
+		CHECK_MALLOC_DO( fd_dump_extend( &buf, &len, &offset, ", destination: "), );
+		CHECK_MALLOC_DO( fd_ep_dump( &buf, &len, &offset, 0, 0, list ), );
+		LOG_D("%s", buf ?: "Error determining SCTP endpoints");
+		free(buf);
+	}
+
 	fd_sa_sdump_numeric(sa_buf, &((struct fd_endpoint *)(list->next))->sa);
 
 	LOG_D("Connecting to SCTP %s:%hu...", sa_buf, port);
 
 	{
-		int ret = fd_sctp_client( &sock, no_ip6, port, list );
+		int ret = fd_sctp_client( &sock, no_ip6, port, list, src_list );
 		if (ret != 0) {
 			LOG_D("SCTP connection to [%s,...] failed: %s", sa_buf, strerror(ret));
 			return NULL;
--- a/libfdcore/cnxctx.h	Thu Apr 30 15:24:47 2020 +1000
+++ b/libfdcore/cnxctx.h	Fri May 01 18:20:33 2020 +1000
@@ -117,7 +117,7 @@
 /* SCTP */
 int fd_sctp_create_bind_server( int * sock, int family, struct fd_list * list, uint16_t port );
 int fd_sctp_listen( int sock );
-int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list );
+int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list, struct fd_list * src_list );
 int fd_sctp_get_local_ep(int sock,  struct fd_list * list);
 int fd_sctp_get_remote_ep(int sock, struct fd_list * list);
 int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary );
--- a/libfdcore/config.c	Thu Apr 30 15:24:47 2020 +1000
+++ b/libfdcore/config.c	Fri May 01 18:20:33 2020 +1000
@@ -147,6 +147,7 @@
 	#endif /* DISABLE_SCTP */
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Pref. proto .. : %s\n", fd_g_config->cnf_flags.pr_tcp ? "TCP" : "SCTP"), return NULL);
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - TLS method ... : %s\n", fd_g_config->cnf_flags.tls_alg ? "INBAND" : "Separate port"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Client bind .. : %s\n", fd_g_config->cnf_flags.no_bind ? "DISABLED" : "Enabled"), return NULL);
 	
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  TLS :   - Certificate .. : %s\n", fd_g_config->cnf_sec_data.cert_file ?: "(NONE)"), return NULL);
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Private key .. : %s\n", fd_g_config->cnf_sec_data.key_file ?: "(NONE)"), return NULL);
@@ -351,7 +352,8 @@
 	}
 	
 	/* Validate local endpoints */
-	if ((!FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) && (fd_g_config->cnf_flags.no_ip4 || fd_g_config->cnf_flags.no_ip6)) {
+	fd_g_config->cnf_flags.no_bind = FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints);
+	if ((!fd_g_config->cnf_flags.no_bind) && (fd_g_config->cnf_flags.no_ip4 || fd_g_config->cnf_flags.no_ip6)) {
 		struct fd_list * li;
 		for ( li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) {
 			struct fd_endpoint * ep = (struct fd_endpoint *)li;
--- a/libfdcore/fdcore-internal.h	Thu Apr 30 15:24:47 2020 +1000
+++ b/libfdcore/fdcore-internal.h	Fri May 01 18:20:33 2020 +1000
@@ -342,7 +342,7 @@
 int             fd_cnx_serv_listen(struct cnxctx * conn);
 struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv);
 struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa, socklen_t addrlen);
-struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list);
+struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list, struct fd_list * src_list);
 int             fd_cnx_start_clear(struct cnxctx * conn, int loop);
 void		fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn);
 int		fd_cnx_proto_info(struct cnxctx * conn, char * buf, size_t len);
--- a/libfdcore/p_cnx.c	Thu Apr 30 15:24:47 2020 +1000
+++ b/libfdcore/p_cnx.c	Fri May 01 18:20:33 2020 +1000
@@ -261,12 +261,14 @@
 		
 		switch (nc->proto) {
 			case IPPROTO_TCP:
+/* TODO: use no_bind and first of cnf_endpoints of nc->ss.sa_family ? */
 				cnx = fd_cnx_cli_connect_tcp((sSA *)&nc->ss, sSAlen(&nc->ss));
 				break;
 #ifndef DISABLE_SCTP			
 			case IPPROTO_SCTP:
 				cnx = fd_cnx_cli_connect_sctp((peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP) ? 1 : fd_g_config->cnf_flags.no_ip6, 
-							nc->port, &peer->p_hdr.info.pi_endpoints);
+							nc->port, &peer->p_hdr.info.pi_endpoints,
+							fd_g_config->cnf_flags.no_bind ? NULL : &fd_g_config->cnf_endpoints);
 				break;
 #endif /* DISABLE_SCTP */
 		}
--- a/libfdcore/sctp.c	Thu Apr 30 15:24:47 2020 +1000
+++ b/libfdcore/sctp.c	Fri May 01 18:20:33 2020 +1000
@@ -869,7 +869,7 @@
 }
 
 /* Create a client socket and connect to remote server */
-int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list )
+int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list, struct fd_list * src_list )
 {
 	int family;
 	union {
@@ -879,11 +879,13 @@
 	size_t size = 0;
 	int count = 0;
 	int ret;
+	int bind_default = 1;	/* enable ASCONF in postbind */
 	
 	sar.buf = NULL;
 	
-	TRACE_ENTRY("%p %i %hu %p", sock, no_ip6, port, list);
+	TRACE_ENTRY("%p %i %hu %p %p", sock, no_ip6, port, list, src_list);
 	CHECK_PARAMS( sock && list && (!FD_IS_LIST_EMPTY(list)) );
+	CHECK_PARAMS( !src_list || (src_list && (!FD_IS_LIST_EMPTY(src_list))) );
 	
 	if (no_ip6) {
 		family = AF_INET;
@@ -899,7 +901,29 @@
 	
 	/* Set the socket options */
 	CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto out );
-	
+
+	/* Bind to explicit source addresses if requested */
+	if (src_list && !FD_IS_LIST_EMPTY(src_list)) {
+		sSA * bindsar = NULL; /* array of addresses */
+		size_t sz = 0; /* size of the array */
+		int sarcount = 0; /* number of sock addr in the array */
+
+		/* Create the array of configured addresses */
+		CHECK_FCT_DO( ret = add_addresses_from_list_mask((void *)&bindsar, &sz, &sarcount, family, 0, src_list, EP_FL_CONF, EP_FL_CONF), goto out );
+
+		if (sarcount) {
+			LOG_A("Bind to local SCTP endpoints (%d addresses attempted) ", sarcount);
+
+			CHECK_SYS_DO( ret = sctp_bindx(*sock, bindsar, sarcount, SCTP_BINDX_ADD_ADDR), goto out );
+		}
+
+		/* Disable ASCONF option in postbind */
+		bind_default = 0;
+
+		/* We don't need bindsar anymore */
+		free(bindsar);
+	}
+
 	/* Create the array of addresses, add first the configured addresses, then the discovered, then the other ones */
 	CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &size, &count, family, htons(port), list, EP_FL_CONF,              EP_FL_CONF	), goto out );
 	CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &size, &count, family, htons(port), list, EP_FL_CONF | EP_FL_DISC, EP_FL_DISC	), goto out );
@@ -944,7 +968,7 @@
 	free(sar.buf); sar.buf = NULL;
 	
 	/* Set the remaining sockopts */
-	CHECK_FCT_DO( ret = fd_setsockopt_postbind(*sock, 1), 
+	CHECK_FCT_DO( ret = fd_setsockopt_postbind(*sock, bind_default),
 		{ 
 			CHECK_SYS_DO( shutdown(*sock, SHUT_RDWR), /* continue */ );
 		} );
--- a/tests/testcnx.c	Thu Apr 30 15:24:47 2020 +1000
+++ b/tests/testcnx.c	Fri May 01 18:20:33 2020 +1000
@@ -674,7 +674,7 @@
 #ifndef DISABLE_SCTP
 		case IPPROTO_SCTP:
 			{
-				cnx = fd_cnx_cli_connect_sctp(0, TEST_PORT, &eps);
+				cnx = fd_cnx_cli_connect_sctp(0, TEST_PORT, &eps, NULL);
 				CHECK( 1, (cnx ? 1 : 0) ^ cf->expect_failure );
 			}
 			break;
--- a/tests/testsctp.c	Thu Apr 30 15:24:47 2020 +1000
+++ b/tests/testsctp.c	Fri May 01 18:20:33 2020 +1000
@@ -98,7 +98,7 @@
 	CHECK( 0, fd_sctp_listen( sock ));
 	
 	/* Now, create the client socket */
-	CHECK( 0, fd_sctp_client( &cli.cc_socket, 0, TEST_PORT, &eps ));
+	CHECK( 0, fd_sctp_client( &cli.cc_socket, 0, TEST_PORT, &eps, NULL ));
 	
 	/* Accept this connection */
 	srv.cc_socket = accept(sock, NULL, NULL);
"Welcome to our mercurial repository"