Mercurial > hg > freeDiameter
changeset 20:277ec00d793e
Backup before typhoon... Progress on server side
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Wed, 07 Oct 2009 19:31:39 +0900 |
parents | 9f28243f5d53 |
children | bef197f6826f |
files | INSTALL doc/freediameter.conf.sample freeDiameter/CMakeLists.txt freeDiameter/cnxctx.c freeDiameter/config.c freeDiameter/fD.h freeDiameter/fdd.y freeDiameter/main.c freeDiameter/p_psm.c freeDiameter/peers.c freeDiameter/sctp.c freeDiameter/server.c include/freeDiameter/freeDiameter.h include/freeDiameter/libfreeDiameter.h |
diffstat | 14 files changed, 575 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/INSTALL Mon Oct 05 17:51:06 2009 +0900 +++ b/INSTALL Wed Oct 07 19:31:39 2009 +0900 @@ -8,7 +8,7 @@ make You can enable the unary tests by doing: -cmake -DNO_TESTS:BOOL=OFF ../ +cmake -DSKIP_TESTS:BOOL=OFF ../ make make tests @@ -37,3 +37,5 @@ You can change the default configuration file pathname: DEFAULT_CONF_FILE:STRING=/path/to/some/freeDiameter.conf +Build binary with symbols, for debug: +CMAKE_BUILD_TYPE:STRING=Debug
--- a/doc/freediameter.conf.sample Mon Oct 05 17:51:06 2009 +0900 +++ b/doc/freediameter.conf.sample Wed Oct 07 19:31:39 2009 +0900 @@ -1,5 +1,7 @@ # This is a sample configuration file for freeDiameter daemon. +# Only the "TLS_Cred" directive is really mandatory in this file. + ############################################################## ## Peer identity and realm @@ -30,11 +32,11 @@ # Default: use RFC3588bis method with separate port for TLS. #TLS_old_method; -# Disable use of TCP protocol (only SCTP) +# Disable use of TCP protocol (only listen and connect in SCTP) # Default : TCP enabled #No_TCP; -# Disable use of SCTP protocol (only TCP) +# Disable use of SCTP protocol (only listen and connect in TCP) # Default : SCTP enabled #No_SCTP; # This option has no effect if freeDiameter is compiled with DISABLE_SCTP option, @@ -92,6 +94,7 @@ # The information about revoked certificates. # The file contains a list of trusted CRLs in PEM format. They should have been verified before. # (This parameter is passed to gnutls_certificate_set_x509_crl_file function) +# Note: currently, openssl CRL seems not supported... # Default : GNUTLS default behavior #TLS_CRL = "<file.PEM>"; @@ -210,3 +213,7 @@ LoadExtension = "extensions/dict_eap.fdx"; ConnectPeer = "jules.nautilus6.org" ; ConnectPeer = "aaa.nautilus6.org" { No_TLS; No_IP; No_TCP; SCTP_streams = 60; } ; +TLS_Cred = "/etc/openssl-ca/clients/certs/fdtest.cert" , "/etc/openssl-ca/clients/privkeys/fdtest.key.pem"; +TLS_CA = "/etc/openssl-ca/public-www/cacert.pem"; +# TLS_CRL = "/etc/openssl-ca/public-www/crl.pem"; +
--- a/freeDiameter/CMakeLists.txt Mon Oct 05 17:51:06 2009 +0900 +++ b/freeDiameter/CMakeLists.txt Wed Oct 07 19:31:39 2009 +0900 @@ -10,6 +10,7 @@ SET(FD_COMMON_SRC fD.h config.c + cnxctx.c dispatch.c extensions.c dict_base_proto.c @@ -18,8 +19,13 @@ peers.c p_expiry.c p_psm.c + server.c ) +IF(NOT DISABLE_SCTP) + SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c) +ENDIF(NOT DISABLE_SCTP) + SET(FD_COMMON_GEN_SRC lex.fdd.c fdd.tab.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/cnxctx.c Wed Oct 07 19:31:39 2009 +0900 @@ -0,0 +1,143 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis <sdecugis@nict.go.jp> * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + +/* Initialize a connection context */ +struct cnxctx * fd_cnx_init(int sock, int proto) +{ + struct cnxctx * conn = NULL; + + TRACE_ENTRY("%d %d", sock, proto); + CHECK_PARAMS_DO( (proto == IPPROTO_TCP) || (proto == IPPROTO_SCTP), return NULL); + + CHECK_MALLOC_DO( conn = malloc(sizeof(struct cnxctx)), return NULL ); + memset(conn, 0, sizeof(struct cnxctx)); + + conn->cc_socket = sock; + conn->cc_proto = proto; + + fd_list_init(&conn->cc_ep_remote, conn); + fd_list_init(&conn->cc_ep_local, conn); + + if (proto == IPPROTO_SCTP) { +#ifndef DISABLE_SCTP + CHECK_FCT_DO( fd_sctp_get_str_info( sock, &conn->cc_sctp_para.str_in, &conn->cc_sctp_para.str_out ), + { free(conn); return NULL; } ); + conn->cc_sctp_para.pairs = (conn->cc_sctp_para.str_out < conn->cc_sctp_para.str_in) ? conn->cc_sctp_para.str_out : conn->cc_sctp_para.str_in; +#else /* DISABLE_SCTP */ + ASSERT(0); +#endif /* DISABLE_SCTP */ + } + + return conn; +} + +/* TLS handshake the connection */ +int fd_cnx_handshake(struct cnxctx * conn, int mode) +{ + TRACE_ENTRY( "%p %d", conn, mode); + CHECK_PARAMS( conn && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) ); + + /* Save the mode */ + conn->cc_tls_para.mode = mode; + + /* Create the master session context */ + CHECK_GNUTLS_DO( gnutls_init (&conn->cc_tls_para.session, mode), return ENOMEM ); + + /* Set the algorithm suite */ + CHECK_GNUTLS_DO( gnutls_priority_set( conn->cc_tls_para.session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL ); + + /* Set the credentials of this side of the connection */ + CHECK_GNUTLS_DO( gnutls_credentials_set (conn->cc_tls_para.session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL ); + + /* Request the remote credentials as well */ + if (mode == GNUTLS_SERVER) { + gnutls_certificate_server_set_request (conn->cc_tls_para.session, GNUTLS_CERT_REQUIRE); + } + + /* Set the socket info in the session */ + gnutls_transport_set_ptr (conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn->cc_socket); + + /* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */ + if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) { +#ifndef DISABLE_SCTP + TODO("Initialize the SCTP TLS wrapper"); + TODO("Set the lowat, push and pull functions"); +#else /* DISABLE_SCTP */ + ASSERT(0); +#endif /* DISABLE_SCTP */ + } + + /* Handshake master session */ + { + int ret; + CHECK_GNUTLS_DO( ret = gnutls_handshake(conn->cc_tls_para.session), + { + if (TRACE_BOOL(INFO)) { + fd_log_debug("TLS Handshake failed on socket %d : %s\n", conn->cc_socket, gnutls_strerror(ret)); + } + return EINVAL; + } ); + + /* Now verify the remote credentials are valid -- only simple test here */ + CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (conn->cc_tls_para.session, &ret), return EINVAL ); + if (ret) { + if (TRACE_BOOL(INFO)) { + fd_log_debug("TLS: Remote certificate invalid on socket %d :\n", conn->cc_socket); + if (ret & GNUTLS_CERT_INVALID) + fd_log_debug(" - The certificate is not trusted (unknown CA?)\n"); + if (ret & GNUTLS_CERT_REVOKED) + fd_log_debug(" - The certificate has been revoked.\n"); + if (ret & GNUTLS_CERT_SIGNER_NOT_FOUND) + fd_log_debug(" - The certificate hasn't got a known issuer.\n"); + if (ret & GNUTLS_CERT_SIGNER_NOT_CA) + fd_log_debug(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.\n"); + if (ret & GNUTLS_CERT_INSECURE_ALGORITHM) + fd_log_debug(" - The certificate signature uses a weak algorithm.\n"); + } + return EINVAL; + } + } + + /* Other sessions in case of multi-stream SCTP are resumed from the master */ + if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) { +#ifndef DISABLE_SCTP + TODO("Init and resume all additional sessions from the master one."); +#endif /* DISABLE_SCTP */ + } + + return 0; +}
--- a/freeDiameter/config.c Mon Oct 05 17:51:06 2009 +0900 +++ b/freeDiameter/config.c Wed Oct 07 19:31:39 2009 +0900 @@ -238,10 +238,12 @@ { TRACE_DEBUG(INFO, "Error in priority string at position : %s", err_pos); return EINVAL; } ); } if (! fd_g_config->cnf_sec_data.dh_bits) { + TRACE_DEBUG(FULL, "Generating DH parameters..."); CHECK_GNUTLS_DO( gnutls_dh_params_generate2( fd_g_config->cnf_sec_data.dh_cache, GNUTLS_DEFAULT_DHBITS), { TRACE_DEBUG(INFO, "Error in DH bits value : %d", GNUTLS_DEFAULT_DHBITS); return EINVAL; } ); + TRACE_DEBUG(FULL, "DH parameters generated."); }
--- a/freeDiameter/fD.h Mon Oct 05 17:51:06 2009 +0900 +++ b/freeDiameter/fD.h Wed Oct 07 19:31:39 2009 +0900 @@ -172,6 +172,40 @@ struct msg *req; /* A request that was sent and not yet answered. */ }; +/* The connection context structure */ +struct cnxctx { + int cc_socket; /* The socket object of the connection -- <=0 if no socket is created */ + + struct fifo **cc_events; /* Location of the events list to send connection events */ + + int cc_proto; /* IPPROTO_TCP or IPPROTO_SCTP */ + int cc_tls; /* Is TLS already started ? */ + + uint16_t cc_port; /* Remote port of the connection, when we are client */ + struct fd_list cc_ep_remote; /* The remote address(es) of the connection */ + struct fd_list cc_ep_local; /* The local address(es) of the connection */ + + /* If cc_proto == SCTP */ + struct { + int str_out;/* Out streams */ + int str_in; /* In streams */ + int pairs; /* max number of pairs ( = min(in, out)) */ + int next; /* # of stream the next message will be sent to */ + } cc_sctp_para; + + /* If cc_tls == true */ + struct { + int mode; /* GNUTLS_CLIENT / GNUTLS_SERVER */ + gnutls_session_t session; /* Session object (stream #0 in case of SCTP) */ + } cc_tls_para; + + /* If both conditions */ + struct { + gnutls_session_t *res_sessions; /* Sessions of other pairs of streams, resumed from the first */ + /* Buffers, threads, ... */ + } cc_sctp_tls_para; +}; + /* Functions */ int fd_peer_fini(); void fd_peer_dump_list(int details); @@ -191,4 +225,22 @@ int fd_psm_terminate(struct fd_peer * peer ); void fd_psm_abord(struct fd_peer * peer ); +/* Server sockets */ +void fd_servers_dump(); +int fd_servers_start(); +void fd_servers_stop(); + +/* Connection contexts */ +struct cnxctx * fd_cnx_init(int sock, int proto); +int fd_cnx_handshake(struct cnxctx * conn, int mode); + +/* SCTP */ +#ifndef DISABLE_SCTP +int fd_sctp_create_bind_server( int * socket, uint16_t port ); +int fd_sctp_get_str_info( int socket, int *in, int *out ); + +#endif /* DISABLE_SCTP */ + + + #endif /* _FD_H */
--- a/freeDiameter/fdd.y Mon Oct 05 17:51:06 2009 +0900 +++ b/freeDiameter/fdd.y Wed Oct 07 19:31:39 2009 +0900 @@ -510,10 +510,12 @@ tls_dh: TLS_DH_BITS '=' INTEGER ';' { conf->cnf_sec_data.dh_bits = $3; + TRACE_DEBUG(FULL, "Generating DH parameters..."); CHECK_GNUTLS_DO( gnutls_dh_params_generate2( conf->cnf_sec_data.dh_cache, conf->cnf_sec_data.dh_bits), { yyerror (&yylloc, conf, "Error setting DH Bits parameters."); YYERROR; } ); + TRACE_DEBUG(FULL, "DH parameters generated."); } ;
--- a/freeDiameter/main.c Mon Oct 05 17:51:06 2009 +0900 +++ b/freeDiameter/main.c Wed Oct 07 19:31:39 2009 +0900 @@ -122,6 +122,10 @@ fd_ext_dump(); break; + case FDEV_DUMP_SERV: + fd_servers_dump(); + break; + case FDEV_DUMP_QUEUES: fd_fifo_dump(0, "Incoming messages", fd_g_incoming, fd_msg_dump_walk); fd_fifo_dump(0, "Outgoing messages", fd_g_outgoing, fd_msg_dump_walk); @@ -170,6 +174,7 @@ case_str(FDEV_TERMINATE); case_str(FDEV_DUMP_DICT); case_str(FDEV_DUMP_EXT); + case_str(FDEV_DUMP_SERV); case_str(FDEV_DUMP_QUEUES); case_str(FDEV_DUMP_CONFIG); case_str(FDEV_DUMP_PEERS);
--- a/freeDiameter/p_psm.c Mon Oct 05 17:51:06 2009 +0900 +++ b/freeDiameter/p_psm.c Wed Oct 07 19:31:39 2009 +0900 @@ -43,6 +43,7 @@ , "STATE_WAITCNXACK" , "STATE_WAITCNXACK_ELEC" , "STATE_WAITCEA" + , "STATE_OPEN_HANDSHAKE" , "STATE_SUSPECT" , "STATE_REOPEN" , "STATE_ZOMBIE"
--- a/freeDiameter/peers.c Mon Oct 05 17:51:06 2009 +0900 +++ b/freeDiameter/peers.c Wed Oct 07 19:31:39 2009 +0900 @@ -343,8 +343,8 @@ peer->p_hdr.info.pi_flags.sec == PI_SEC_DEFAULT ? "" : (peer->p_hdr.info.pi_flags.sec == PI_SEC_NONE ? "IPSec." : "InbandTLS."), peer->p_hdr.info.pi_flags.exp ? "Expire." : "", - peer->p_hdr.info.pi_flags.inband & PI_INB_NONE ? "InbandIPsecOK." : "", - peer->p_hdr.info.pi_flags.inband & PI_INB_TLS ? "InbandTLSOK." : "", + peer->p_hdr.info.pi_flags.inband_none ? "InbandIPsec." : "", + peer->p_hdr.info.pi_flags.inband_tls ? "InbandTLS." : "", peer->p_hdr.info.pi_flags.relay ? "Relay (0xffffff)" : "No relay" ); fd_log_debug("\tLifetime : %d sec\n", peer->p_hdr.info.pi_lft);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/sctp.c Wed Oct 07 19:31:39 2009 +0900 @@ -0,0 +1,50 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis <sdecugis@nict.go.jp> * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + +int fd_sctp_create_bind_server( int * socket, uint16_t port ) +{ + TODO("Create sctp server, using fd_g_config: cnf_endpoints, no_ip4, no_ip6, cnf_sctp_str"); + + return ENOTSUP; +} + +int fd_sctp_get_str_info( int socket, int *in, int *out ) +{ + TODO("Retrieve streams info from the socket"); + + return ENOTSUP; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/server.c Wed Oct 07 19:31:39 2009 +0900 @@ -0,0 +1,273 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis <sdecugis@nict.go.jp> * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + +/* This file contains the server (listening) part of the daemon */ + +struct fd_list FD_SERVERS = FD_LIST_INITIALIZER(FD_SERVERS); /* The list of all server sockets */ +/* We don't need to protect this list, it is only accessed from the main thread. */ + +/* Server (listening socket) information */ +struct server { + struct fd_list chain; /* link in the FD_SERVERS list */ + + int socket; /* server socket, or <= 0 */ + + int proto; /* IPPROTO_TCP or IPPROTO_SCTP */ + int secur; /* TLS is started immediatly after connection ? */ + + pthread_t serv_thr; /* The thread listening for new connections */ + int serv_status; /* 0 : not created; 1 : running; 2 : terminated */ + + pthread_mutex_t clients_mtx; /* Mutex to protect the list of clients connected to the thread */ + struct fd_list clients; /* The list of clients connecting to this server, which information is not yet known */ + + char * serv_name; /* A string to identify this server */ +}; + +/* Client (connected remote endpoint, not received CER yet) information */ +struct client { + struct fd_list chain; /* link in the server's list of clients */ + + struct cnxctx *conn; /* Parameters of the connection; sends its events to the ev fifo bellow */ + + struct timespec ts; /* Delay for receiving CER: INCNX_TIMEOUT */ + struct fifo *ev; /* Events of the connection -- allowed: TIMEOUT, ERROR (cnx, tls), MSG_RCV (CER, other=>error) */ + + pthread_t cli_thr; /* connection state machine (simplified PSM) */ +}; + +/* Parameter for the thread handling the new connected client, to avoid bloking the server thread */ +struct cli_fast { + struct server * serv; + int sock; + sSS ss; + socklen_t sslen; +}; + + +/* This thread is called when a new client had just connected */ +static void * handle_client_fast(void * arg) +{ + struct cli_fast * cf = arg; + struct client * c = NULL; + + /* Name the current thread */ + ASSERT(arg); + { + char addr[128]; + int offset = snprintf(addr, sizeof(addr), "Srv %d/Cli %d : ", cf->serv->socket, cf->sock); + int rc = getnameinfo((sSA *)&cf->ss, sizeof(sSS), addr + offset, sizeof(addr) - offset, NULL, 0, 0); + if (rc) + memcpy(addr + offset, gai_strerror(rc), sizeof(addr) - offset); + + if (TRACE_BOOL(INFO)) { + fd_log_debug( "New connection %s, sock %d, from '%s'\n", cf->serv->serv_name, cf->sock, addr + offset); + } + + fd_log_threadname ( addr ); + } + + /* Create a client structure */ + CHECK_MALLOC_DO( c = malloc(sizeof(struct client)), goto early_error ); + memset(c, 0, sizeof(struct client)); + fd_list_init(&c->chain, c); + c->cli_thr = pthread_self(); + + /* Create the connection context */ + CHECK_MALLOC_DO( c->conn = fd_cnx_init(cf->sock, cf->serv->proto), goto early_error ); + + /* In case we are a secure server, handshake now */ + if (cf->serv->secur) { + + TODO("Continue"); + } + + /* Save the client in the list */ + CHECK_POSIX_DO( pthread_mutex_lock( &cf->serv->clients_mtx ), goto early_error ); + fd_list_insert_before(&cf->serv->clients, &c->chain); + CHECK_POSIX_DO( pthread_mutex_unlock( &cf->serv->clients_mtx ), goto error ); + + + + +early_error: + TRACE_DEBUG(INFO, "Thread is detaching to die"); + pthread_detach(pthread_self()); + shutdown(cf->sock, SHUT_RDWR); + free(cf); + free(c); +error: + TRACE_DEBUG(INFO, "Thread is terminating"); + CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), ); + return NULL; +} + +/* The thread for the server */ +static void * serv_th(void * arg) +{ + struct server *sv = (struct server *)arg; + struct cli_fast cf; + + CHECK_PARAMS_DO(sv, goto error); + fd_log_threadname ( sv->serv_name ); + sv->serv_status = 1; + + memset(&cf, 0, sizeof(struct cli_fast)); + cf.serv = sv; + + + /* Accept incoming connections */ + CHECK_SYS_DO( listen(sv->socket, 5), goto error ); + + do { + struct cli_fast * ncf; + pthread_t thr; + + /* Re-init socket size */ + cf.sslen = sizeof(sSS); + + /* Wait for a new client */ + CHECK_SYS_DO( cf.sock = accept(sv->socket, (sSA *)&cf.ss, &cf.sslen), goto error ); + + TRACE_DEBUG(FULL, "New connection accepted"); + + /* Create the copy for the client thread */ + CHECK_MALLOC_DO( ncf = malloc(sizeof(struct cli_fast)), goto error ); + memcpy(ncf, &cf, sizeof(struct cli_fast)); + + /* Create the thread to handle the new incoming connection */ + CHECK_POSIX_DO( pthread_create( &thr /* we don't use it, but NULL is not standard */, NULL, handle_client_fast, ncf), goto error ); + + } while (1); + +error: + if (sv) + sv->serv_status = 2; + /* Send error signal to the daemon */ + TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating..."); + CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), ); + + return NULL; +} + + +/* Create a new server structure */ +static struct server * new_serv( int proto, int secur, int socket ) +{ + char buf[32]; + char * sn = NULL; + struct server * new; + + /* Create the server debug name */ + buf[sizeof(buf) - 1] = '\0'; + snprintf(buf, sizeof(buf) - 1, "Serv %d (%s%s)", socket, IPPROTO_NAME( proto ), secur ? "s" : ""); + CHECK_MALLOC_DO( sn = strdup(buf), return NULL ); + + /* New server structure */ + CHECK_MALLOC_DO( new = malloc(sizeof(struct server)), return NULL ); + + memset(new, 0, sizeof(struct server)); + fd_list_init(&new->chain, new); + new->socket = socket; + new->proto = proto; + new->secur = secur; + CHECK_POSIX_DO( pthread_mutex_init(&new->clients_mtx, NULL), return NULL ); + fd_list_init(&new->clients, new); + + new->serv_name = sn; + + return new; +} + +/* Dump all servers information */ +void fd_servers_dump() +{ + struct fd_list * li; + + fd_log_debug("Dumping servers list :\n"); + for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) { + struct server * sv = (struct server *)li; + fd_log_debug(" Serv '%s': %s(%d), %s, %s, %s\n", + sv->serv_name, + (sv->socket > 0) ? "Open" : "Closed", sv->socket, + IPPROTO_NAME( sv->proto ), + sv->secur ? "Secur" : "NotSecur", + (sv->serv_status == 0) ? "Thread not created" : + ((sv->serv_status == 1) ? "Thread running" : + ((sv->serv_status == 2) ? "Thread terminated" : + "Thread status unknown"))); + /* Dump the endpoints ? */ + /* Dump the client list ? */ + } +} + +/* Start all the servers */ +int fd_servers_start() +{ + int socket; + struct server * sv; + + /* SCTP */ + if (!fd_g_config->cnf_flags.no_sctp) { +#ifdef DISABLE_SCTP + ASSERT(0); +#else /* DISABLE_SCTP */ + + /* Create the server on default port */ + CHECK_FCT( fd_sctp_create_bind_server( &socket, fd_g_config->cnf_port ) ); + CHECK_MALLOC( sv = new_serv(IPPROTO_SCTP, 0, socket) ); + + + + +#endif /* DISABLE_SCTP */ + } + + /* TCP */ + if (!fd_g_config->cnf_flags.no_tcp) { + + + } + + return 0; +} + +/* Terminate all the servers */ +void fd_servers_stop() +{ + +}
--- a/include/freeDiameter/freeDiameter.h Mon Oct 05 17:51:06 2009 +0900 +++ b/include/freeDiameter/freeDiameter.h Wed Oct 07 19:31:39 2009 +0900 @@ -117,7 +117,7 @@ /* Endpoints */ struct fd_endpoint { struct fd_list chain; /* link in cnf_endpoints list */ - sSS ss; /* the socket information. */ + sSS ss; /* the socket information. List is always ordered by ss value (memcmp) */ struct { unsigned conf : 1; /* This endpoint is statically configured in a configuration file */ unsigned disc : 1; /* This endpoint was resolved from the Diameter Identity or other DNS query */ @@ -174,11 +174,12 @@ FDEV_TERMINATE = 1000 /* request to terminate */ ,FDEV_DUMP_DICT /* Dump the content of the dictionary */ ,FDEV_DUMP_EXT /* Dump state of extensions */ + ,FDEV_DUMP_SERV /* Dump the server socket status */ ,FDEV_DUMP_QUEUES /* Dump the message queues */ ,FDEV_DUMP_CONFIG /* Dump the configuration */ ,FDEV_DUMP_PEERS /* Dump the list of peers */ }; -const char * fd_ev_str(int event); +const char * fd_ev_str(int event); /* defined in freeDiameter/main.c */ /***************************************/ @@ -201,6 +202,7 @@ We have sent a CER on our initiated connection, and received a CER from the remote peer on another connection. Election. If we win the election, we must disconnect the initiated connection and send a CEA on the other => we go to OPEN state. If we lose, we disconnect the other connection (receiver) and fallback to WAITCEA state. */ + STATE_OPEN_HANDSHAKE, /* TLS Handshake and validation are in progress in open state */ /* Failover state machine */ STATE_SUSPECT, /* A DWR was sent and not answered within TwTime. Failover in progress. */ @@ -210,7 +212,7 @@ STATE_ZOMBIE /* The PSM thread is not running anymore; it must be re-started or peer should be deleted. */ #define STATE_MAX STATE_ZOMBIE }; -extern const char *peer_state_str[]; +extern const char *peer_state_str[]; /* defined in freeDiameter/p_psm.c */ #define STATE_STR(state) \ (((unsigned)(state)) <= STATE_MAX ? peer_state_str[((unsigned)(state)) ] : "<Invalid>") @@ -244,10 +246,8 @@ #define PI_EXP_INACTIVE 1 /* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */ unsigned exp :1; - /* Following flags are read-only and received from remote peer */ - #define PI_INB_NONE 1 /* Remote peer advertised inband-sec-id 0 (None) */ - #define PI_INB_TLS 2 /* Remote peer advertised inband-sec-id 1 (TLS) */ - unsigned inband :2; /* This is only meaningful with pi_flags.sec == 3 */ + unsigned inband_none :1; /* This is only meaningful with pi_flags.sec == 3 */ + unsigned inband_tls :1; /* This is only meaningful with pi_flags.sec == 3 */ unsigned relay :1; /* The remote peer advertized the relay application */ @@ -337,17 +337,29 @@ * 0 : The callback is added. * !0 : An error occurred. */ -int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */) ); +int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) ); /* * CALLBACK: peer_validate * * PARAMETERS: * info : Structure containing information about the peer attempting the connection. * auth : Store there the result if the peer is accepted (1), rejected (-1), or unknown (0). + * cb2 : If != NULL and in case of PI_SEC_TLS_OLD, another callback to call after handshake (if auth = 1). * * DESCRIPTION: * This callback is called when a new connection is being established from an unknown peer, - * after the CER is received. An extension must register such callback with peer_validate_register. + * after the CER is received. An extension must register such callback with peer_validate_register. + * + * If (info->pi_flags.sec == PI_SEC_TLS_OLD) the extension may instruct the daemon explicitely + * to not use TLS by clearing info->pi_flags.inband_tls -- only if inband_none is set. + * + * If (info->pi_flags.sec == PI_SEC_TLS_OLD) and info->pi_flags.inband_tls is set, + * the extension may also need to check the credentials provided during the TLS + * exchange (remote certificate). For this purpose, it may set the address of a new callback + * to be called once the handshake is completed. This new callback receives the information + * structure as parameter (with pi_sec_data set) and returns 0 if the credentials are correct, + * or an error code otherwise. If the error code is received, the connection is closed and the + * peer is destroyed. * * RETURN VALUE: * 0 : The authorization decision has been written in the location pointed by auth.
--- a/include/freeDiameter/libfreeDiameter.h Mon Oct 05 17:51:06 2009 +0900 +++ b/include/freeDiameter/libfreeDiameter.h Wed Oct 07 19:31:39 2009 +0900 @@ -336,6 +336,12 @@ } /* if needed, add sSA_DUMP_SERVICE */ +/* A l4 protocol name (TCP / SCTP) */ +#define IPPROTO_NAME( _proto ) \ + ( ((_proto) == IPPROTO_TCP) ? "TCP" : \ + (((_proto) == IPPROTO_SCTP) ? "SCTP" : \ + "Unknown")) + /* The sockaddr length of a sSS structure */ #define sSSlen( _ss_ ) \ ( (socklen_t) ( ((_ss_)->ss_family == AF_INET) ? (sizeof(sSA4)) : \