Commit 468f5fe8 authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

Try to fix the old bug on sctp_getpaddrs

parent d854e3ce
......@@ -121,8 +121,10 @@ struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint *
}
if (sa->sa_family == AF_INET) {
((sSA4 *)sa)->sin_port = htons(port);
cnx->cc_family = AF_INET;
} else {
((sSA6 *)sa)->sin6_port = htons(port);
cnx->cc_family = AF_INET6;
}
/* Create the socket */
......@@ -166,8 +168,14 @@ struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list)
/* The connection object */
CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL );
if (fd_g_config->cnf_flags.no_ip6) {
cnx->cc_family = AF_INET;
} else {
cnx->cc_family = AF_INET6; /* can create socket for both IP and IPv6 */
}
/* Create the socket */
CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, ep_list, port ), goto error );
CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, cnx->cc_family, ep_list, port ), goto error );
/* Generate the name for the connection object */
snprintf(cnx->cc_id, sizeof(cnx->cc_id), "SCTP srv :%hu (%d)", port, cnx->cc_socket);
......@@ -228,6 +236,7 @@ struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv)
CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); close(cli_sock); return NULL; } );
cli->cc_socket = cli_sock;
cli->cc_family = serv->cc_family;
cli->cc_proto = serv->cc_proto;
/* Set the timeout */
......@@ -296,6 +305,7 @@ struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa /* contains the port already */,
CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); close(sock); return NULL; } );
cnx->cc_socket = sock;
cnx->cc_family = sa->sa_family;
cnx->cc_proto = IPPROTO_TCP;
/* Set the timeout */
......@@ -346,6 +356,7 @@ struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_lis
CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); close(sock); return NULL; } );
cnx->cc_socket = sock;
cnx->cc_family = no_ip6 ? AF_INET : AF_INET6;
cnx->cc_proto = IPPROTO_SCTP;
/* Set the timeout */
......
......@@ -45,6 +45,7 @@ struct cnxctx {
int cc_socket; /* The socket object of the connection -- <=0 if no socket is created */
int cc_family; /* AF_INET or AF_INET6 (mixed) */
int cc_proto; /* IPPROTO_TCP or IPPROTO_SCTP */
uint32_t cc_status; /* True if the object is being destroyed: we don't send events anymore */
#define CC_STATUS_CLOSING 1
......@@ -101,10 +102,10 @@ int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl);
#ifndef DISABLE_SCTP
/* SCTP */
int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port );
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_get_local_ep(int sock, struct fd_list * 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 );
int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len, int * cc_closing);
......
......@@ -585,21 +585,107 @@ static int fd_setsockopt_postbind(int sk, int bound_to_default)
return 0;
}
/* Create a socket server and bind it according to daemon s configuration */
int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port )
/* Add addresses from a list to an array, with filter on the flags */
static int add_addresses_from_list_mask(uint8_t ** array, size_t * size, int * addr_count, int target_family, uint16_t port, struct fd_list * list, uint32_t mask, uint32_t val)
{
int family;
int bind_default;
struct fd_list * li;
int to_add4 = 0;
int to_add6 = 0;
union {
uint8_t *buf;
sSA4 *sin;
sSA6 *sin6;
} ptr;
size_t sz;
TRACE_ENTRY("%p %p %hu", sock, list, port);
CHECK_PARAMS(sock);
/* First, count the number of addresses to add */
for (li = list->next; li != list; li = li->next) {
struct fd_endpoint * ep = (struct fd_endpoint *) li;
/* Do the flag match ? */
if ((val & mask) != (ep->flags & mask))
continue;
if (ep->sa.sa_family == AF_INET) {
to_add4 ++;
} else {
to_add6 ++;
}
}
if (fd_g_config->cnf_flags.no_ip6) {
family = AF_INET;
if ((to_add4 + to_add6) == 0)
return 0; /* nothing to do */
/* The size to add */
if (target_family == AF_INET) {
sz = to_add4 * sizeof(sSA4);
} else {
family = AF_INET6; /* can create socket for both IP and IPv6 */
#ifndef SCTP_USE_MAPPED_ADDRESSES
sz = (to_add4 * sizeof(sSA4)) + (to_add6 * sizeof(sSA6));
#else /* SCTP_USE_MAPPED_ADDRESSES */
sz = (to_add4 + to_add6) * sizeof(sSA6);
#endif /* SCTP_USE_MAPPED_ADDRESSES */
}
/* Now, (re)alloc the array to store the new addresses */
CHECK_MALLOC( *array = realloc(*array, *size + sz) );
/* Finally, add the addresses */
for (li = list->next; li != list; li = li->next) {
struct fd_endpoint * ep = (struct fd_endpoint *) li;
/* Skip v6 addresses for v4 socket */
if ((target_family == AF_INET) && (ep->sa.sa_family == AF_INET6))
continue;
/* Are the flags matching ? */
if ((val & mask) != (ep->flags & mask))
continue;
/* Size of the new SA we are adding (array may contain a mix of sockaddr_in and sockaddr_in6) */
#ifndef SCTP_USE_MAPPED_ADDRESSES
if (ep->sa.sa_family == AF_INET6)
#else /* SCTP_USE_MAPPED_ADDRESSES */
if (target_family == AF_INET6) {
#endif /* SCTP_USE_MAPPED_ADDRESSES */
sz = sizeof(sSA6);
else
sz = sizeof(sSA4);
/* Place where we add the new address */
ptr.buf = *array + *size; /* place of the new SA */
/* Update other information */
*size += sz;
*addr_count += 1;
/* And write the addr in the buffer */
if (sz == sizeof(sSA4)) {
memcpy(ptr.buf, &ep->sin, sz);
ptr.sin->sin_port = port;
} else {
if (ep->sa.sa_family == AF_INET) { /* We must map the address */
memset(ptr.buf, 0, sz);
ptr.sin6->sin6_family = AF_INET6;
IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr );
} else {
memcpy(ptr.sin6, &ep->sin6, sz);
}
ptr.sin6->sin6_port = port;
}
}
return 0;
}
/* Create a socket server and bind it according to daemon s configuration */
int fd_sctp_create_bind_server( int * sock, int family, struct fd_list * list, uint16_t port )
{
int bind_default;
TRACE_ENTRY("%p %i %p %hu", sock, family, list, port);
CHECK_PARAMS(sock);
/* Create the socket */
CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) );
......@@ -632,62 +718,12 @@ redo:
} else {
/* Explicit endpoints to bind to from config */
union {
sSA * sa;
sSA4 *sin;
sSA6 *sin6;
uint8_t *buf;
} ptr;
union {
sSA * sa;
uint8_t * buf;
} sar;
int count = 0; /* number of sock addr in sar array */
size_t offset = 0;
struct fd_list * li;
sar.buf = NULL;
sSA * sar = NULL; /* array of addresses */
size_t sz = 0; /* size of the array */
int count = 0; /* number of sock addr in the array */
/* Create a flat array from the list of configured addresses */
for (li = list->next; li != list; li = li->next) {
struct fd_endpoint * ep = (struct fd_endpoint *)li;
size_t sz = 0;
if (! (ep->flags & EP_FL_CONF))
continue;
count++;
/* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */
#ifndef SCTP_USE_MAPPED_ADDRESSES
if (ep->sa.sa_family == AF_INET6)
#else /* SCTP_USE_MAPPED_ADDRESSES */
if (family == AF_INET6)
#endif /* SCTP_USE_MAPPED_ADDRESSES */
sz = sizeof(sSA6);
else
sz = sizeof(sSA4);
/* augment sar to contain the additional info */
CHECK_MALLOC( sar.buf = realloc(sar.buf, offset + sz) );
ptr.buf = sar.buf + offset; /* place of the new SA */
offset += sz; /* update to end of sar */
if (sz == sizeof(sSA4)) {
memcpy(ptr.buf, &ep->sin, sz);
ptr.sin->sin_port = htons(port);
} else {
if (ep->sa.sa_family == AF_INET) { /* We must map the address */
memset(ptr.buf, 0, sz);
ptr.sin6->sin6_family = AF_INET6;
IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr );
} else {
memcpy(ptr.sin6, &ep->sin6, sz);
}
ptr.sin6->sin6_port = htons(port);
}
}
/* Create the array of configured addresses */
CHECK_FCT( add_addresses_from_list_mask((void *)&sar, &sz, &count, family, port, list, EP_FL_CONF, EP_FL_CONF) );
if (!count) {
/* None of the addresses in the list came from configuration, we bind to default */
......@@ -696,8 +732,12 @@ redo:
}
if (TRACE_BOOL(SCTP_LEVEL)) {
union {
sSA *sa;
uint8_t *buf;
} ptr;
int i;
ptr.buf = sar.buf;
ptr.sa = sar;
fd_log_debug("Calling sctp_bindx with the following address array:\n");
for (i = 0; i < count; i++) {
TRACE_DEBUG_sSA(FULL, " - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );
......@@ -706,10 +746,10 @@ redo:
}
/* Bind to this array */
CHECK_SYS( sctp_bindx(*sock, sar.sa, count, SCTP_BINDX_ADD_ADDR) );
CHECK_SYS( sctp_bindx(*sock, sar, count, SCTP_BINDX_ADD_ADDR) );
/* We don't need sar anymore */
free(sar.buf);
free(sar);
}
/* Now, the server is bound, set remaining sockopt */
......@@ -744,71 +784,16 @@ int fd_sctp_listen( int sock )
return 0;
}
/* Add addresses from the list that match the flags to the array */
static int add_addresses_from_list_mask(uint8_t ** array, int * count, size_t * offset, uint16_t port, struct fd_list * list, uint32_t mask, uint32_t val)
{
size_t sz;
struct fd_list * li;
union {
uint8_t *buf;
sSA4 *sin;
sSA6 *sin6;
} ptr;
for (li = list->next; li != list; li = li->next) {
struct fd_endpoint * ep = (struct fd_endpoint *) li;
/* Do the flag match ? */
if ((val & mask) != (ep->flags & mask))
continue;
/* We add this endpoint at the end of array */
(*count)++;
/* Size of the new SA we are adding (array may contain a mix of sockaddr_in and sockaddr_in6) */
#ifndef SCTP_USE_MAPPED_ADDRESSES
if (ep->sa.sa_family == AF_INET6)
#else /* SCTP_USE_MAPPED_ADDRESSES */
if (family == AF_INET6)
#endif /* SCTP_USE_MAPPED_ADDRESSES */
sz = sizeof(sSA6);
else
sz = sizeof(sSA4);
/* augment array to contain the additional info */
CHECK_MALLOC( *array = realloc(*array, (*offset) + sz) );
ptr.buf = *array + *offset; /* place of the new SA */
(*offset) += sz; /* update to end of sar */
if (sz == sizeof(sSA4)) {
memcpy(ptr.buf, &ep->sin, sz);
ptr.sin->sin_port = port;
} else {
if (ep->sa.sa_family == AF_INET) { /* We must map the address */
memset(ptr.buf, 0, sz);
ptr.sin6->sin6_family = AF_INET6;
IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr );
} else {
memcpy(ptr.sin6, &ep->sin6, sz);
}
ptr.sin6->sin6_port = port;
}
}
return 0;
}
/* 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 family;
int count = 0;
size_t offset = 0;
union {
uint8_t *buf;
sSA *sa;
} sar;
size_t size = 0;
int count = 0;
int ret;
sar.buf = NULL;
......@@ -832,9 +817,9 @@ int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list
CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto fail );
/* 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, &count, &offset, htons(port), list, EP_FL_CONF, EP_FL_CONF ), goto fail );
CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &count, &offset, htons(port), list, EP_FL_CONF | EP_FL_DISC, EP_FL_DISC ), goto fail );
CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &count, &offset, htons(port), list, EP_FL_CONF | EP_FL_DISC, 0 ), goto fail );
CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &size, &count, family, htons(port), list, EP_FL_CONF, EP_FL_CONF ), goto fail );
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 fail );
CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &size, &count, family, htons(port), list, EP_FL_CONF | EP_FL_DISC, 0 ), goto fail );
/* Try connecting */
if (TRACE_BOOL(FULL)) {
......@@ -860,10 +845,6 @@ int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list
CHECK_SYS_DO( sctp_connectx(*sock, sar.sa, count), { ret = errno; goto fail; } );
#endif /* SCTP_CONNECTX_4_ARGS */
/*****************
BUG : received "EINVAL" at reconnection attempt... Should probably filter what is in that list !
*****************/
free(sar.buf); sar.buf = NULL;
/* Set the remaining sockopts */
......@@ -936,7 +917,7 @@ int fd_sctp_get_local_ep(int sock, struct fd_list * list)
uint8_t *buf;
} ptr;
sSA * data;
sSA * data = NULL;
int count;
TRACE_ENTRY("%d %p", sock, list);
......@@ -953,13 +934,17 @@ int fd_sctp_get_local_ep(int sock, struct fd_list * list)
case AF_INET6: sl = sizeof(sSA6); break;
default:
TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getladdrs: %d", ptr.sa->sa_family);
TRACE_DEBUG_BUFFER(NONE, "DEBUG: Parsed data : [", data, ptr.buf - (uint8_t *)data, "]" );
TRACE_DEBUG(NONE, "DEBUG: Remaining %d addresses to parse in :", count)
TRACE_DEBUG_BUFFER(NONE, "DEBUG: Unable to parse [", ptr.buf, count * sizeof(sSA), "]" );
goto stop;
}
CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) );
ptr.buf += sl;
count --;
}
stop:
/* Free the list */
sctp_freeladdrs(data);
......@@ -993,9 +978,6 @@ int fd_sctp_get_remote_ep(int sock, struct fd_list * list)
CHECK_SYS( count = sctp_getpaddrs(sock, 0, &data) );
ptr.sa = data;
TRACE_DEBUG(NONE, "DEBUG: count = %d", count);
TRACE_DEBUG_BUFFER(NONE, "DEBUG: data = ", ptr.buf, count * sizeof(sSA4), "" );
while (count) {
socklen_t sl;
switch (ptr.sa->sa_family) {
......@@ -1003,14 +985,17 @@ int fd_sctp_get_remote_ep(int sock, struct fd_list * list)
case AF_INET6: sl = sizeof(sSA6); break;
default:
TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getpaddrs: %d, skip", ptr.sa->sa_family);
goto next;
TRACE_DEBUG_BUFFER(NONE, "DEBUG: Parsed data : [", data, ptr.buf - (uint8_t *)data, "]" );
TRACE_DEBUG(NONE, "DEBUG: Remaining %d addresses to parse in :", count)
TRACE_DEBUG_BUFFER(NONE, "DEBUG: Unable to parse [", ptr.buf, count * sizeof(sSA), "]" );
goto stop;
}
CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) );
ptr.buf += sl;
count --;
}
next:
stop:
/* Free the list */
sctp_freepaddrs(data);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment