# HG changeset patch # User Luke Mewburn # Date 1588321233 -36000 # Node ID 407e0a889c7e01562050b466c67a7ee18c121fe0 # Parent d25ce064c6677d364853cdb9bc0ca060f0e73b87 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. diff -r d25ce064c667 -r 407e0a889c7e include/freeDiameter/libfdcore.h --- 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 { diff -r d25ce064c667 -r 407e0a889c7e libfdcore/cnxctx.c --- 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; diff -r d25ce064c667 -r 407e0a889c7e libfdcore/cnxctx.h --- 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 ); diff -r d25ce064c667 -r 407e0a889c7e libfdcore/config.c --- 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; diff -r d25ce064c667 -r 407e0a889c7e libfdcore/fdcore-internal.h --- 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); diff -r d25ce064c667 -r 407e0a889c7e libfdcore/p_cnx.c --- 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 */ } diff -r d25ce064c667 -r 407e0a889c7e libfdcore/sctp.c --- 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 */ ); } ); diff -r d25ce064c667 -r 407e0a889c7e tests/testcnx.c --- 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; diff -r d25ce064c667 -r 407e0a889c7e tests/testsctp.c --- 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);