# HG changeset patch # User Sebastien Decugis # Date 1278314482 -32400 # Node ID 41e3c2a3721ce898e18b20f8c4340bb9db3fd813 # Parent 7c0ddec9ab42fe77c260fb126c3dc215c67b6909 Replaced old mechanism to discover local addresses by a call to getifaddrs, lot cleaner! Should close #4 diff -r 7c0ddec9ab42 -r 41e3c2a3721c freeDiameter/cnxctx.c --- a/freeDiameter/cnxctx.c Mon Jul 05 14:36:50 2010 +0900 +++ b/freeDiameter/cnxctx.c Mon Jul 05 16:21:22 2010 +0900 @@ -36,11 +36,15 @@ #include "fD.h" #include "cnxctx.h" +#include +#include /* 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 @@ } /* 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; + break; - #ifndef DISABLE_SCTP - case IPPROTO_SCTP: { - CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, remote)); - } - break; - #endif /* DISABLE_SCTP */ + #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); - } + 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 @@ 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 */ diff -r 7c0ddec9ab42 -r 41e3c2a3721c freeDiameter/cnxctx.h --- a/freeDiameter/cnxctx.h Mon Jul 05 14:36:50 2010 +0900 +++ b/freeDiameter/cnxctx.h Mon Jul 05 16:21:22 2010 +0900 @@ -136,5 +136,8 @@ #endif /* DISABLE_SCTP */ +/* UDP */ +int fd_cnx_get_local_eps(struct fd_list * list); + #endif /* _CNXCTX_H */ diff -r 7c0ddec9ab42 -r 41e3c2a3721c freeDiameter/fD.h --- a/freeDiameter/fD.h Mon Jul 05 14:36:50 2010 +0900 +++ b/freeDiameter/fD.h Mon Jul 05 16:21:22 2010 +0900 @@ -326,7 +326,7 @@ 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 */ diff -r 7c0ddec9ab42 -r 41e3c2a3721c freeDiameter/p_ce.c --- a/freeDiameter/p_ce.c Mon Jul 05 14:36:50 2010 +0900 +++ b/freeDiameter/p_ce.c Mon Jul 05 16:21:22 2010 +0900 @@ -62,7 +62,7 @@ } /* 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 @@ 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 @@ /* 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 @@ 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 ) ); diff -r 7c0ddec9ab42 -r 41e3c2a3721c freeDiameter/p_psm.c --- a/freeDiameter/p_psm.c Mon Jul 05 14:36:50 2010 +0900 +++ b/freeDiameter/p_psm.c Mon Jul 05 16:21:22 2010 +0900 @@ -570,9 +570,9 @@ 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):" ); diff -r 7c0ddec9ab42 -r 41e3c2a3721c freeDiameter/sctp.c --- a/freeDiameter/sctp.c Mon Jul 05 14:36:50 2010 +0900 +++ b/freeDiameter/sctp.c Mon Jul 05 16:21:22 2010 +0900 @@ -932,54 +932,6 @@ 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) { diff -r 7c0ddec9ab42 -r 41e3c2a3721c freeDiameter/server.c --- a/freeDiameter/server.c Mon Jul 05 14:36:50 2010 +0900 +++ b/freeDiameter/server.c Mon Jul 05 16:21:22 2010 +0900 @@ -269,15 +269,6 @@ 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 @@ } } + /* 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; } diff -r 7c0ddec9ab42 -r 41e3c2a3721c freeDiameter/tcp.c --- a/freeDiameter/tcp.c Mon Jul 05 14:36:50 2010 +0900 +++ b/freeDiameter/tcp.c Mon Jul 05 16:21:22 2010 +0900 @@ -169,19 +169,6 @@ 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 @@ return 0; } + diff -r 7c0ddec9ab42 -r 41e3c2a3721c include/freeDiameter/CMakeLists.txt --- a/include/freeDiameter/CMakeLists.txt Mon Jul 05 14:36:50 2010 +0900 +++ b/include/freeDiameter/CMakeLists.txt Mon Jul 05 16:21:22 2010 +0900 @@ -42,6 +42,11 @@ # 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)