Index: libfdcore/cnxctx.c
===================================================================
--- libfdcore/cnxctx.c	(revision 1419)
+++ libfdcore/cnxctx.c	(revision 1540)
@@ -331,6 +331,7 @@
 }
 
-/* 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
@@ -345,7 +346,24 @@
 	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);
 
@@ -353,5 +371,5 @@
 
 	{
-		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));
Index: libfdcore/cnxctx.h
===================================================================
--- libfdcore/cnxctx.h	(revision 1421)
+++ libfdcore/cnxctx.h	(revision 1540)
@@ -118,5 +118,5 @@
 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);
Index: libfdcore/config.c
===================================================================
--- libfdcore/config.c	(revision 1415)
+++ libfdcore/config.c	(revision 1540)
@@ -148,4 +148,5 @@
 	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);
@@ -352,5 +353,6 @@
 	
 	/* 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) {
Index: libfdcore/fdcore-internal.h
===================================================================
--- libfdcore/fdcore-internal.h	(revision 1397)
+++ libfdcore/fdcore-internal.h	(revision 1540)
@@ -343,5 +343,5 @@
 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);
Index: libfdcore/p_cnx.c
===================================================================
--- libfdcore/p_cnx.c	(revision 1203)
+++ libfdcore/p_cnx.c	(revision 1540)
@@ -262,4 +262,5 @@
 		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;
@@ -267,5 +268,6 @@
 			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 */
Index: libfdcore/sctp.c
===================================================================
--- libfdcore/sctp.c	(revision 1543)
+++ libfdcore/sctp.c	(revision 1544)
@@ -59,4 +59,32 @@
 #endif /* USE_DEFAULT_SCTP_RTX_PARAMS */
 
+
+DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_array, sSA * saddrs, int saddrs_count)
+{
+	union {
+		sSA	*sa;
+		uint8_t *buf;
+	} ptr;
+	int i;
+	int salen;
+
+	FD_DUMP_HANDLE_OFFSET();
+
+	ptr.sa = saddrs;
+	for (i = 0; i < saddrs_count; i++) {
+		salen = sSAlen(ptr.sa);
+		if (salen == 0) {
+			LOG_E("fd_sa_dump_array: Unknown sockaddr family");
+			break;
+		}
+		if (i > 0) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " "), return NULL);
+		}
+		CHECK_MALLOC_DO( fd_sa_dump( FD_DUMP_STD_PARAMS, ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV), return NULL);
+		ptr.buf += salen;
+	}
+	return *buf;
+}
+
 /* Pre-binding socket options -- # streams read in config */
 static int fd_setsockopt_prebind(int sk)
@@ -815,19 +843,14 @@
 			goto redo;
 		}
-		
-		#if 0
-			union {
-				sSA	*sa;
-				uint8_t *buf;
-			} ptr;
-			int i;
-			ptr.sa = sar;
-			fd_log_debug("Calling sctp_bindx with the following address array:");
-			for (i = 0; i < count; i++) {
-				TRACE_sSA(FD_LOG_DEBUG, FULL, "    - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );
-				ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6) ;
-			}
-		#endif
-		
+
+		/* Debug: show bound addresses */
+		{
+			char * buf = NULL;
+			size_t len = 0;
+			CHECK_MALLOC_DO( fd_sa_dump_array( &buf, &len, 0, sar, count), );
+			LOG_D("SCTP server binding local addresses: %s", buf);
+			free(buf);
+		}
+
 		/* Bind to this array */
 		CHECK_SYS(  sctp_bindx(*sock, sar, count, SCTP_BINDX_ADD_ADDR)  );
@@ -841,20 +864,17 @@
 	
 	/* Debug: show all local listening addresses */
-	#if 0
-		sSA *sar;
-		union {
-			sSA	*sa;
-			uint8_t *buf;
-		} ptr;
-		int sz;
-		
+	{
+		sSA *sar = NULL;
+		int sz = 0;
+		char * buf = NULL;
+		size_t len = 0;
+
 		CHECK_SYS(  sz = sctp_getladdrs(*sock, 0, &sar)  );
-		
-		fd_log_debug("SCTP server bound on :");
-		for (ptr.sa = sar; sz-- > 0; ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6)) {
-			TRACE_sSA(FD_LOG_DEBUG, FULL, "    - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );
-		}
+
+		CHECK_MALLOC_DO( fd_sa_dump_array( &buf, &len, 0, sar, sz), );
+		LOG_D("SCTP server locally bound addresses: %s", buf);
 		sctp_freeladdrs(sar);
-	#endif
+		free(buf);
+	}
 
 	return 0;
@@ -870,5 +890,5 @@
 
 /* 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;
@@ -880,9 +900,11 @@
 	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) {
@@ -900,5 +922,31 @@
 	/* 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) {
+			char * buf = NULL;
+			size_t len = 0;
+			CHECK_MALLOC_DO( fd_sa_dump_array( &buf, &len, 0, bindsar, sarcount), goto out );
+			LOG_A("SCTP client binding local addresses: %s", buf);
+			free(buf);
+
+			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 );
@@ -907,22 +955,12 @@
 	
 	/* Try connecting */
-	LOG_A("Attempting SCTP connection (%d addresses attempted) ", count);
-		
-#if 0
-		/* Dump the SAs */
-		union {
-			uint8_t *buf;
-			sSA	*sa;
-			sSA4	*sin;
-			sSA6	*sin6;
-		} ptr;
-		int i;
-		ptr.buf = sar.buf;
-		for (i=0; i< count; i++) {
-			TRACE_sSA(FD_LOG_DEBUG, FULL, "  - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );
-			ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6);
-		}
-#endif
-	
+	{
+		char * buf = NULL;
+		size_t len = 0;
+		CHECK_MALLOC_DO( fd_sa_dump_array( &buf, &len, 0, sar.sa, count), goto out );
+		LOG_A("SCTP client connecting to addresses: %s", buf);
+		free(buf);
+	}
+
 	/* Bug in some Linux kernel, the sctp_connectx is not a cancellation point. To avoid blocking freeDiameter, we allow async cancel here */
 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
@@ -945,5 +983,5 @@
 	
 	/* 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 */ );
@@ -983,5 +1021,5 @@
 #if 0
 		char sa_buf[sSA_DUMP_STRLEN];
-		fd_sa_sdump_numeric(sa_buf, &status.sstat_primary.spinfo_address);
+		fd_sa_sdump_numeric(sa_buf, (sSA *)&status.sstat_primary.spinfo_address);
 		fd_log_debug( "SCTP_STATUS : sstat_state                  : %i" , status.sstat_state);
 		fd_log_debug( "              sstat_rwnd  	          : %u" , status.sstat_rwnd);
@@ -1219,4 +1257,5 @@
 	if (mhdr.msg_flags & MSG_NOTIFICATION) {
 		union sctp_notification * notif = (union sctp_notification *) data;
+		char sa_buf[sSA_DUMP_STRLEN];
 		
 		TRACE_DEBUG(FULL, "Received %zdb data of notification on socket %d", datasize, conn->cc_socket);
@@ -1236,5 +1275,6 @@
 			case SCTP_PEER_ADDR_CHANGE:
 				TRACE_DEBUG(FULL, "Received SCTP_PEER_ADDR_CHANGE notification");
-				/* TRACE_sSA(FD_LOG_DEBUG, ANNOYING, "    intf_change : ", &(notif->sn_paddr_change.spc_aaddr), NI_NUMERICHOST | NI_NUMERICSERV, "" ); */
+				fd_sa_sdump_numeric(sa_buf, (sSA *)&(notif->sn_paddr_change.spc_aaddr));
+				TRACE_DEBUG(ANNOYING, "    intf_change : %s", sa_buf);
 				TRACE_DEBUG(ANNOYING, "          state : %d", notif->sn_paddr_change.spc_state);
 				TRACE_DEBUG(ANNOYING, "          error : %d", notif->sn_paddr_change.spc_error);
