Commit abe94b31 authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

Replaced old mechanism to discover local addresses by a call to getifaddrs, lot cleaner!

Should close #4
parent 812eb679
......@@ -36,11 +36,15 @@
#include "fD.h"
#include "cnxctx.h"
#include <net/if.h>
#include <ifaddrs.h> /* for getifaddrs */
/* The maximum size of Diameter message we accept to receive (<= 2^24) to avoid too big mallocs in case of trashed headers */
#ifndef DIAMETER_MSG_SIZE_MAX
#define DIAMETER_MSG_SIZE_MAX 65535 /* in bytes */
#endif /* DIAMETER_MSG_SIZE_MAX */
/* Connections contexts (cnxctx) in freeDiameter are wrappers around the sockets and TLS operations .
* They are used to hide the details of the processing to the higher layers of the daemon.
* They are always oriented on connections (TCP or SCTP), connectionless modes (UDP or SCTP) are not supported.
......@@ -73,7 +77,6 @@
* - fd_cnx_destroy
*/
/*******************************************/
/* Creation of a connection object */
/*******************************************/
......@@ -467,64 +470,38 @@ int fd_cnx_getTLS(struct cnxctx * conn)
}
/* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */
int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote)
int fd_cnx_getremoteeps(struct cnxctx * conn, struct fd_list * eps)
{
TRACE_ENTRY("%p %p %p", conn, local, remote);
CHECK_PARAMS(conn);
TRACE_ENTRY("%p %p %p", conn, eps);
CHECK_PARAMS(conn && eps);
if (local) {
/* Retrieve the local endpoint(s) of the connection */
switch (conn->cc_proto) {
case IPPROTO_TCP: {
sSS ss;
socklen_t sl;
CHECK_FCT(fd_tcp_get_local_ep(conn->cc_socket, &ss, &sl));
CHECK_FCT(fd_ep_add_merge( local, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY));
}
break;
/* Check we have a full connection object, not a listening socket (with no remote) */
CHECK_PARAMS( conn->cc_incoming );
#ifndef DISABLE_SCTP
case IPPROTO_SCTP: {
CHECK_FCT(fd_sctp_get_local_ep(conn->cc_socket, local));
}
break;
#endif /* DISABLE_SCTP */
default:
CHECK_PARAMS(0);
/* Retrieve the peer endpoint(s) of the connection */
switch (conn->cc_proto) {
case IPPROTO_TCP: {
sSS ss;
socklen_t sl;
CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl));
CHECK_FCT(fd_ep_add_merge( eps, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY ));
}
}
if (remote) {
/* Check we have a full connection object, not a listening socket (with no remote) */
CHECK_PARAMS( conn->cc_incoming );
/* Retrieve the peer endpoint(s) of the connection */
switch (conn->cc_proto) {
case IPPROTO_TCP: {
sSS ss;
socklen_t sl;
CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl));
CHECK_FCT(fd_ep_add_merge( remote, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY ));
}
break;
#ifndef DISABLE_SCTP
case IPPROTO_SCTP: {
CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, remote));
}
break;
#endif /* DISABLE_SCTP */
break;
default:
CHECK_PARAMS(0);
#ifndef DISABLE_SCTP
case IPPROTO_SCTP: {
CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, eps));
}
break;
#endif /* DISABLE_SCTP */
default:
CHECK_PARAMS(0);
}
return 0;
}
/* Get a string describing the remote peer address (ip address or fqdn) */
char * fd_cnx_getremoteid(struct cnxctx * conn)
{
......@@ -532,6 +509,30 @@ char * fd_cnx_getremoteid(struct cnxctx * conn)
return conn->cc_remid;
}
/* Retrieve a list of all IP addresses of the local system from the kernel, using */
int fd_cnx_get_local_eps(struct fd_list * list)
{
struct ifaddrs *iflist, *cur;
CHECK_SYS(getifaddrs(&iflist));
for (cur = iflist; cur != NULL; cur = cur->ifa_next) {
if (cur->ifa_flags & IFF_LOOPBACK)
continue;
if (fd_g_config->cnf_flags.no_ip4 && (cur->ifa_addr->sa_family == AF_INET))
continue;
if (fd_g_config->cnf_flags.no_ip6 && (cur->ifa_addr->sa_family == AF_INET6))
continue;
CHECK_FCT(fd_ep_add_merge( list, cur->ifa_addr, sSAlen(cur->ifa_addr), EP_FL_LL ));
}
freeifaddrs(iflist);
return 0;
}
/**************************************/
/* Use of a connection object */
......
......@@ -136,5 +136,8 @@ void fd_sctps_destroy(struct cnxctx * conn);
#endif /* DISABLE_SCTP */
/* UDP */
int fd_cnx_get_local_eps(struct fd_list * list);
#endif /* _CNXCTX_H */
......@@ -326,7 +326,7 @@ char * fd_cnx_getid(struct cnxctx * conn);
int fd_cnx_getproto(struct cnxctx * conn);
int fd_cnx_getTLS(struct cnxctx * conn);
int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size);
int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote);
int fd_cnx_getremoteeps(struct cnxctx * conn, struct fd_list * eps);
char * fd_cnx_getremoteid(struct cnxctx * conn);
int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len);
int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo); /* send FDEVP_CNX_MSG_RECV event to the fifo list */
......
......@@ -62,7 +62,7 @@ static int set_peer_cnx(struct fd_peer * peer, struct cnxctx **cnx)
}
/* Read the endpoints, maybe used to reconnect to the peer later */
CHECK_FCT( fd_cnx_getendpoints(peer->p_cnxctx, NULL, &peer->p_hdr.info.pi_endpoints) );
CHECK_FCT( fd_cnx_getremoteeps(peer->p_cnxctx, &peer->p_hdr.info.pi_endpoints) );
/* Read the protocol */
peer->p_hdr.info.runtime.pir_proto = fd_cnx_getproto(peer->p_cnxctx);
......@@ -105,7 +105,7 @@ static int add_CE_info(struct msg *msg, struct cnxctx * cnx, int isi_tls, int is
struct dict_object * dictobj = NULL;
struct avp * avp = NULL;
union avp_value val;
struct fd_list *li, local_ep = FD_LIST_INITIALIZER(local_ep);
struct fd_list *li;
/* Add the Origin-* AVPs */
CHECK_FCT( fd_msg_add_origin ( msg, 1 ) );
......@@ -113,11 +113,8 @@ static int add_CE_info(struct msg *msg, struct cnxctx * cnx, int isi_tls, int is
/* Find the model for Host-IP-Address AVP */
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Host-IP-Address", &dictobj, ENOENT ) );
/* Get the list of endpoints */
CHECK_FCT( fd_cnx_getendpoints(cnx, &local_ep, NULL) );
/* Add the AVP(s) -- not sure what is the purpose... We could probably only add the primary one ? */
for (li = local_ep.next; li != &local_ep; li = li->next) {
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;
CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
......@@ -125,7 +122,6 @@ static int add_CE_info(struct msg *msg, struct cnxctx * cnx, int isi_tls, int is
CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
}
/* Vendor-Id, Product-Name, and Firmware-Revision AVPs */
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Id", &dictobj, ENOENT ) );
CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
......
......@@ -570,9 +570,9 @@ psm_loop:
CHECK_FCT_DO( fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_PRIMARY ), /* ignore the error */);
/* Get the new ones */
CHECK_FCT_DO( fd_cnx_getendpoints(peer->p_cnxctx, NULL, &peer->p_hdr.info.pi_endpoints), /* ignore the error */);
CHECK_FCT_DO( fd_cnx_getremoteeps(peer->p_cnxctx, &peer->p_hdr.info.pi_endpoints), /* ignore the error */);
/* We do not support local endpoints change currently, but it could be added here if needed */
/* We do not support local endpoints change currently, but it could be added here if needed (refresh fd_g_config->cnf_endpoints)*/
if (TRACE_BOOL(ANNOYING)) {
TRACE_DEBUG(ANNOYING, "New remote endpoint(s):" );
......
......@@ -932,54 +932,6 @@ int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary )
return 0;
}
/* Get the list of local endpoints of the socket */
int fd_sctp_get_local_ep(int sock, struct fd_list * list)
{
union {
sSA *sa;
uint8_t *buf;
} ptr;
sSA * data = NULL;
int count;
TRACE_ENTRY("%d %p", sock, list);
CHECK_PARAMS(list);
/* Read the list on the socket */
CHECK_SYS( count = sctp_getladdrs(sock, 0, &data) );
ptr.sa = data;
while (count) {
socklen_t sl;
switch (ptr.sa->sa_family) {
case AF_INET: sl = sizeof(sSA4); break;
case AF_INET6: sl = sizeof(sSA6); break;
default:
TRACE_DEBUG(INFO, "Unknown address family returned in sctp_getladdrs: %d", ptr.sa->sa_family);
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);
/* Now get the primary address, the add function will take care of merging with existing entry */
{
sSS ss;
socklen_t sl = sizeof(sSS);
CHECK_SYS(getsockname(sock, (sSA *)&ss, &sl));
CHECK_FCT( fd_ep_add_merge( list, (sSA *)&ss, sl, EP_FL_PRIMARY ) );
}
return 0;
}
/* Get the list of remote endpoints of the socket */
int fd_sctp_get_remote_ep(int sock, struct fd_list * list)
{
......
......@@ -269,15 +269,6 @@ int fd_servers_start()
fd_list_insert_before( &FD_SERVERS, &s->chain );
CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
/* Retrieve the list of endpoints if it was empty */
if (empty_conf_ep) {
(void) fd_cnx_getendpoints(s->conn, &fd_g_config->cnf_endpoints, NULL);
if (TRACE_BOOL(FULL)){
fd_log_debug(" Local server address(es) :\n");
fd_ep_dump( 5, &fd_g_config->cnf_endpoints );
}
}
/* Create the server on secure port */
CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 1) );
CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port_tls, FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints) ? NULL : &fd_g_config->cnf_endpoints) );
......@@ -343,6 +334,18 @@ int fd_servers_start()
}
}
/* Now, if we still have not got the list of local adresses, try to read it from the kernel directly */
if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
CHECK_FCT(fd_cnx_get_local_eps(&fd_g_config->cnf_endpoints));
if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
TRACE_DEBUG(INFO, "Unable to find the addresses of the local system. Please use \"ListenOn\" parameter in the configuration.");
return EINVAL;
}
}
if (TRACE_BOOL(FULL)){
fd_log_debug(" Local server address(es) :\n");
fd_ep_dump( 5, &fd_g_config->cnf_endpoints );
}
return 0;
}
......
......@@ -169,19 +169,6 @@ int fd_tcp_client( int *sock, sSA * sa, socklen_t salen )
return ret;
}
/* Get the local name of a TCP socket -- would be nice if it did not return "0.0.0.0"... */
int fd_tcp_get_local_ep(int sock, sSS * ss, socklen_t *sl)
{
TRACE_ENTRY("%d %p %p", sock, ss, sl);
CHECK_PARAMS( ss && sl );
*sl = sizeof(sSS);
CHECK_SYS(getsockname(sock, (sSA *)ss, sl));
return 0;
}
/* Get the remote name of a TCP socket */
int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl)
{
......@@ -193,3 +180,4 @@ int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl)
return 0;
}
......@@ -42,6 +42,11 @@ CHECK_SYMBOL_EXISTS(ntohll "" HAVE_NTOHLL)
# malloc.h ?
CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H)
# getifaddrs ?
CHECK_FUNCTION_EXISTS (getifaddrs HAVE_GETIFADDRS)
IF (NOT HAVE_GETIFADDRS)
MESSAGE(SEND_ERROR "The getifaddrs function is currently required by freeDiameter.")
ENDIF (NOT HAVE_GETIFADDRS)
# pthreads
INCLUDE(FindThreads)
......
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