Commit 3df3caad authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

Added support in configuration file for peers declaration

parent ba423f26
......@@ -6,23 +6,23 @@
# The Diameter Identity of this daemon.
# This must be a valid FQDN that resolves to the local host.
# Default: hostname's FQDN
#LocalIdentity = "aaa.koganei.wide.ad.jp";
#Identity = "aaa.koganei.wide.ad.jp";
# The Diameter Realm of this daemon.
# Default: the domain part of LocalIdentity.
#LocalRealm = "wide.ad.jp";
# Default: the domain part of Identity.
#Realm = "wide.ad.jp";
##############################################################
## Transport protocol configuration
# The port this peer is listening on for incoming connections (TCP and SCTP).
# Default: 3868
#LocalPort = 3868;
#Port = 3868;
# The port this peer is listening on for incoming TLS connections (TCP and SCTP).
# See TLS_old_method for more information.
# Default: 3869
#LocalSecPort = 3869;
#SecPort = 3869;
# Use RFC3588 method for TLS protection, where TLS is negociated after CER/CEA
# on the same port. This only affects outgoing connections. It can be overwritten
......@@ -93,7 +93,7 @@
# Default: Relaying is enabled.
#NoRelay;
# Other applications are configured by extensions.
# Other applications are configured by loading appropriate extensions.
##############################################################
## Extensions configuration
......@@ -104,21 +104,51 @@
# by loadable extensions (plug-ins).
# These extensions may in addition receive the name of a
# configuration file, the format of which is extension-specific.
#
# Format:
#LoadExtension = "/path/to/extension" [ : "/optional/configuration/file" ] ;
#
# Exemples:
#LoadExtension = "extensions/sample.so";
#LoadExtension = "extensions/sample.so":"conf/sample.conf";
##############################################################
## Peers configuration
# The local server listens for incoming connections. By default,
# all unknown connecting peers are rejected. Extensions can override this behavior.
#
# In addition to incoming connections, the local peer can
# be configured to establish and maintain connections to some
# Diameter nodes and allow connections from these nodes.
# This is achieved with the ConnectPeer directive described bellow.
#
# Note that the configured Diameter Id MUST match
# the information received inside CEA, or the connection will be aborted.
#
# Format:
#ConnectPeer = "diameterid" [ { parameter1; parameter2; ...} ] ;
# Parameters that can be specified in the peer's parameter list:
# No_TCP; No_SCTP; No_IP; No_IPv6; Prefer_TCP; TLS_old_method;
# No_TLS; # assume transparent security instead of TLS
# Port = 3868; # The port to connect to
# SCTP_streams = 30;
# TcTimer = 30;
# TwTimer = 30;
# ConnectTo = "202.249.37.5";
# ConnectTo = "2001:200:903:2::202:1";
# Examples:
#ConnectPeer = "aaa.wide.ad.jp";
#ConnectPeer = "old.diameter.serv" { TcTimer = 60; TLS_old_method; No_SCTP; } ;
##############################################################
# -------- Test configuration ---------
LocalIdentity = "aaa.koganei.wide.ad.jp";
LocalRealm = "wide.ad.jp";
LocalPort = 3866;
LocalSecPort = 3867;
Identity = "aaa.koganei.wide.ad.jp";
Realm = "wide.ad.jp";
Port = 3866;
SecPort = 3867;
TLS_old_method;
No_IP;
Prefer_TCP;
......@@ -131,3 +161,4 @@ NoRelay;
LoadExtension = "extensions/dbg_monitor.fdx";
LoadExtension = "extensions/dict_nasreq.fdx";
LoadExtension = "extensions/dict_eap.fdx";
ConnectPeer = "jules.nautilus6.org" ;
......@@ -71,18 +71,89 @@ int fd_dict_base_protocol(struct dictionary * dict);
/* Peers */
struct fd_peer { /* The "real" definition of the peer structure */
struct peer_hdr p_hdr; /* contains all public data */
/* The public data */
struct peer_hdr p_hdr;
int p_eyec; /* Eye catcher, EYEC_PEER */
/* Eye catcher, EYEC_PEER */
int p_eyec;
#define EYEC_PEER 0x373C9336
/* threads, message queues, socket & callbacks */
/* Origin of this peer object, for debug */
char *p_dbgorig;
/* Mutex that protect this peer structure */
pthread_mutex_t p_mtx;
/* Reference counter -- freed only when this reaches 0 */
unsigned p_refcount;
/* Chaining in peers sublists */
struct fd_list p_expiry; /* list of expiring peers, ordered by their timeout value */
struct fd_list p_actives; /* list of peers in the STATE_OPEN state -- faster routing creation */
/* The next hop-by-hop id value for the link */
uint32_t p_hbh;
/* Some flags influencing the peer state machine */
struct {
unsigned pf_responder : 1; /* The local peer is responder on the connection */
unsigned pf_dw_pending : 1; /* A DWR message was sent and not answered yet */
unsigned pf_cnx_pb : 1; /* The peer was disconnected because of watchdogs; must exchange 3 watchdogs before putting back to normal */
unsigned pf_reopen_cnt : 2; /* remaining DW to be exchanged after re-established connection */
/* to be completed */
} p_flags;
/* The events queue, peer state machine thread, timer for states timeouts */
struct fifo *p_events;
pthread_t p_psm;
struct timespec p_psm_timer;
/* Received message queue, and thread managing reception of messages */
struct fifo *p_recv;
pthread_t p_inthr;
/* Outgoing message queue, and thread managing sending the messages */
struct fifo *p_tosend;
pthread_t p_outthr;
/* Sent requests (for fallback), list of struct sentreq ordered by hbh */
struct fd_list p_sentreq;
/* connection context: socket & other metadata */
struct cnxctx *p_cnxctx;
};
#define CHECK_PEER( _p ) \
(((_p) != NULL) && (((struct fd_peer *)(_p))->p_eyec == EYEC_PEER))
/* Events codespace for struct fd_peer->p_events */
enum {
/* request to terminate this peer : disconnect, requeue all messages */
FDEVP_TERMINATE = 2000
/* Dump all info about this peer in the debug log */
,FDEVP_DUMP_ALL
/* A message was received in the peer */
,FDEVP_MSG_INCOMING
};
/* Structure to store a sent request */
struct sentreq {
struct fd_list chain; /* the "o" field points directly to the hop-by-hop of the request (uint32_t *) */
struct msg *req; /* A request that was sent and not yet answered. */
};
/* Functions */
int fd_peer_init();
void fd_peer_dump(int details);
void fd_peer_dump_list(int details);
int fd_peer_start();
int fd_peer_waitstart();
#endif /* _FD_H */
......@@ -111,10 +111,10 @@ qstring \"[^\"\n]*\"
}
/* Full words tokens (keywords) */
(?i:"LocalIdentity") { return LOCALIDENTITY; }
(?i:"LocalRealm") { return LOCALREALM; }
(?i:"LocalPort") { return LOCALPORT; }
(?i:"LocalSecPort") { return LOCALSECPORT; }
(?i:"Identity") { return IDENTITY; }
(?i:"Realm") { return REALM; }
(?i:"Port") { return PORT; }
(?i:"SecPort") { return SECPORT; }
(?i:"No_IPv6") { return NOIP6; }
(?i:"No_IP") { return NOIP; }
(?i:"No_TCP") { return NOTCP; }
......@@ -127,6 +127,9 @@ qstring \"[^\"\n]*\"
(?i:"TwTimer") { return TWTIMER; }
(?i:"NoRelay") { return NORELAY; }
(?i:"LoadExtension") { return LOADEXT; }
(?i:"ConnectPeer") { return CONNPEER; }
(?i:"ConnectTo") { return CONNTO; }
(?i:"No_TLS") { return NOTLS; }
/* Valid single characters for yyparse */
......
......@@ -69,12 +69,19 @@ void yyerror (YYLTYPE *ploc, struct fd_config * conf, char const *s)
fprintf(stderr, "%s:%d.%d : %s\n", conf->cnf_file, ploc->first_line, ploc->first_column, s);
}
int got_peer_noip = 0;
int got_peer_noipv6 = 0;
int got_peer_notcp = 0;
int got_peer_nosctp = 0;
struct peer_info fddpi;
%}
/* Values returned by lex for token */
%union {
char *string; /* The string is allocated by strdup in lex.*/
int integer; /* Store integer values */
char *string; /* The string is allocated by strdup in lex.*/
int integer; /* Store integer values */
}
/* In case of error in the lexical analysis */
......@@ -83,24 +90,27 @@ void yyerror (YYLTYPE *ploc, struct fd_config * conf, char const *s)
%token <string> QSTRING
%token <integer> INTEGER
%type <string> extconf
%type <string> extconf
%token LOCALIDENTITY
%token LOCALREALM
%token LOCALPORT
%token LOCALSECPORT
%token IDENTITY
%token REALM
%token PORT
%token SECPORT
%token NOIP
%token NOIP6
%token NOTCP
%token NOSCTP
%token PREFERTCP
%token OLDTLS
%token NOTLS
%token SCTPSTREAMS
%token LISTENON
%token TCTIMER
%token TWTIMER
%token NORELAY
%token LOADEXT
%token CONNPEER
%token CONNTO
/* -------------------------------------- */
......@@ -108,12 +118,12 @@ void yyerror (YYLTYPE *ploc, struct fd_config * conf, char const *s)
/* The grammar definition - Sections blocs. */
conffile: /* Empty is OK */
| conffile localidentity
| conffile localrealm
| conffile identity
| conffile realm
| conffile tctimer
| conffile twtimer
| conffile localport
| conffile localsecport
| conffile port
| conffile secport
| conffile sctpstreams
| conffile listenon
| conffile norelay
......@@ -124,15 +134,26 @@ conffile: /* Empty is OK */
| conffile prefertcp
| conffile oldtls
| conffile loadext
| conffile connpeer
| conffile errors
{
yyerror(&yylloc, conf, "An error occurred while parsing the configuration file");
return EINVAL;
}
;
localidentity: LOCALIDENTITY '=' QSTRING ';'
/* Lexical or syntax error */
errors: LEX_ERROR
| error
;
identity: IDENTITY '=' QSTRING ';'
{
conf->cnf_diamid = $3;
}
;
localrealm: LOCALREALM '=' QSTRING ';'
realm: REALM '=' QSTRING ';'
{
conf->cnf_diamrlm = $3;
}
......@@ -154,7 +175,7 @@ twtimer: TWTIMER '=' INTEGER ';'
}
;
localport: LOCALPORT '=' INTEGER ';'
port: PORT '=' INTEGER ';'
{
CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16),
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
......@@ -162,7 +183,7 @@ localport: LOCALPORT '=' INTEGER ';'
}
;
localsecport: LOCALSECPORT '=' INTEGER ';'
secport: SECPORT '=' INTEGER ';'
{
CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16),
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
......@@ -209,24 +230,54 @@ norelay: NORELAY ';'
noip: NOIP ';'
{
if (got_peer_noipv6) {
yyerror (&yylloc, conf, "No_IP conflicts with a ConnectPeer directive No_IPv6.");
YYERROR;
}
conf->cnf_flags.no_ip4 = 1;
}
;
noip6: NOIP6 ';'
{
if (got_peer_noip) {
yyerror (&yylloc, conf, "No_IP conflicts with a ConnectPeer directive No_IP.");
YYERROR;
}
conf->cnf_flags.no_ip6 = 1;
}
;
notcp: NOTCP ';'
{
#ifdef DISABLE_SCTP
yyerror (&yylloc, conf, "No_TCP cannot be specified for daemon compiled with DISABLE_SCTP option.");
YYERROR;
#endif
if (conf->cnf_flags.no_sctp)
{
yyerror (&yylloc, conf, "No_TCP conflicts with No_SCTP directive." );
YYERROR;
}
if (got_peer_nosctp) {
yyerror (&yylloc, conf, "No_TCP conflicts with a ConnectPeer directive No_SCTP.");
YYERROR;
}
conf->cnf_flags.no_tcp = 1;
}
;
nosctp: NOSCTP ';'
{
if (conf->cnf_flags.no_tcp)
{
yyerror (&yylloc, conf, "No_SCTP conflicts with No_TCP directive." );
YYERROR;
}
if (got_peer_notcp) {
yyerror (&yylloc, conf, "No_SCTP conflicts with a ConnectPeer directive No_TCP.");
YYERROR;
}
conf->cnf_flags.no_sctp = 1;
}
;
......@@ -259,3 +310,130 @@ extconf: /* empty */
$$ = $2;
}
;
connpeer: {
memset(&fddpi, 0, sizeof(fddpi));
}
CONNPEER '=' QSTRING peerinfo ';'
{
fddpi.pi_diamid = $4;
CHECK_FCT_DO( fd_peer_add ( &fddpi, conf->cnf_file, NULL, NULL ),
{ yyerror (&yylloc, conf, "Error adding ConnectPeer information"); YYERROR; } );
/* Now destroy any content in the structure */
free(fddpi.pi_diamid);
while (!FD_IS_LIST_EMPTY(&fddpi.pi_endpoints)) {
struct fd_list * li = fddpi.pi_endpoints.next;
fd_list_unlink(li);
free(li);
}
}
;
peerinfo: /* empty */
| '{' peerparams '}'
;
peerparams: /* empty */
| peerparams NOIP ';'
{
if ((conf->cnf_flags.no_ip6) || (fddpi.pi_flags.pro3 == PI_P3_IP)) {
yyerror (&yylloc, conf, "No_IP conflicts with a No_IPv6 directive.");
YYERROR;
}
got_peer_noip++;
fddpi.pi_flags.pro3 = PI_P3_IPv6;
}
| peerparams NOIP6 ';'
{
if ((conf->cnf_flags.no_ip4) || (fddpi.pi_flags.pro3 == PI_P3_IPv6)) {
yyerror (&yylloc, conf, "No_IPv6 conflicts with a No_IP directive.");
YYERROR;
}
got_peer_noipv6++;
fddpi.pi_flags.pro3 = PI_P3_IP;
}
| peerparams NOTCP ';'
{
#ifdef DISABLE_SCTP
yyerror (&yylloc, conf, "No_TCP cannot be specified in daemon compiled with DISABLE_SCTP option.");
YYERROR;
#endif
if ((conf->cnf_flags.no_sctp) || (fddpi.pi_flags.pro4 == PI_P4_TCP)) {
yyerror (&yylloc, conf, "No_TCP conflicts with a No_SCTP directive.");
YYERROR;
}
got_peer_notcp++;
fddpi.pi_flags.pro4 = PI_P4_SCTP;
}
| peerparams NOSCTP ';'
{
if ((conf->cnf_flags.no_tcp) || (fddpi.pi_flags.pro4 == PI_P4_SCTP)) {
yyerror (&yylloc, conf, "No_SCTP conflicts with a No_TCP directive.");
YYERROR;
}
got_peer_nosctp++;
fddpi.pi_flags.pro4 = PI_P4_TCP;
}
| peerparams PREFERTCP ';'
{
fddpi.pi_flags.alg = PI_ALGPREF_TCP;
}
| peerparams OLDTLS ';'
{
if (fddpi.pi_flags.sec == PI_SEC_NONE) {
yyerror (&yylloc, conf, "ConnectPeer: TLS_old_method conflicts with No_TLS.");
YYERROR;
}
fddpi.pi_flags.sec = PI_SEC_TLS_OLD;
}
| peerparams NOTLS ';'
{
if (fddpi.pi_flags.sec == PI_SEC_TLS_OLD) {
yyerror (&yylloc, conf, "ConnectPeer: No_TLS conflicts with TLS_old_method.");
YYERROR;
}
fddpi.pi_flags.sec = PI_SEC_NONE;
}
| peerparams PORT '=' INTEGER ';'
{
CHECK_PARAMS_DO( ($4 > 0) && ($4 < 1<<16),
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
fddpi.pi_port = (uint16_t)$4;
}
| peerparams SCTPSTREAMS '=' INTEGER ';'
{
CHECK_PARAMS_DO( ($4 > 0) && ($4 < 1<<16),
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
fddpi.pi_streams = (uint16_t)$4;
}
| peerparams TCTIMER '=' INTEGER ';'
{
fddpi.pi_tctimer = $4;
}
| peerparams TWTIMER '=' INTEGER ';'
{
fddpi.pi_twtimer = $4;
}
| peerparams CONNTO '=' QSTRING ';'
{
struct fd_endpoint * ep;
struct addrinfo hints, *ai;
int ret;
CHECK_MALLOC_DO( ep = malloc(sizeof(struct fd_endpoint)),
{ yyerror (&yylloc, conf, "Out of memory"); YYERROR; } );
memset(ep, 0, sizeof(struct fd_endpoint));
fd_list_init(&ep->chain, NULL);
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_ADDRCONFIG;
ret = getaddrinfo($4, NULL, &hints, &ai);
if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen);
free($4);
freeaddrinfo(ai);
fd_list_insert_before(&fddpi.pi_endpoints, &ep->chain);
}
;
......@@ -116,7 +116,7 @@ int main(int argc, char * argv[])
break;
case FDEV_DUMP_PEERS:
fd_peer_dump(FULL);
fd_peer_dump_list(FULL);
break;
case FDEV_TERMINATE:
......
......@@ -46,8 +46,6 @@ const char *peer_state_str[] = { "<error>"
, "STATE_SUSPECT"
, "STATE_REOPEN"
};
#define STATE_STR(state) \
peer_state_str[ (state) <= STATE_REOPEN ? (state) : 0 ]
struct fd_list fd_g_peers;
pthread_rwlock_t fd_g_peers_rw;
......@@ -93,7 +91,7 @@ int fd_peer_init()
}
/* Dump the list of peers */
void fd_peer_dump(int details)
void fd_peer_dump_list(int details)
{
struct fd_list * li;
......@@ -107,14 +105,21 @@ void fd_peer_dump(int details)
continue;
}
fd_log_debug(" %s %s", np->p_hdr.info.pi_diamid, STATE_STR(np->p_hdr.info.pi_state));
fd_log_debug(" %s\t%s", STATE_STR(np->p_hdr.info.pi_state), np->p_hdr.info.pi_diamid);
if (details > INFO) {
fd_log_debug(" (rlm:%s)", np->p_hdr.info.pi_realm);
fd_log_debug("\t(rlm:%s)", np->p_hdr.info.pi_realm);
if (np->p_hdr.info.pi_prodname)
fd_log_debug(" ['%s' %u]", np->p_hdr.info.pi_prodname, np->p_hdr.info.pi_firmrev);
fd_log_debug("\t['%s' %u]", np->p_hdr.info.pi_prodname, np->p_hdr.info.pi_firmrev);
fd_log_debug("\t(from %s)", np->p_dbgorig);
}
fd_log_debug("\n");
}
CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
}
/* Add a new peer entry */
int fd_peer_add ( struct peer_info * info, char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data )
{
return ENOTSUP;
}
......@@ -124,12 +124,12 @@ static __inline__ int fd_event_get(struct fifo *queue, int *code, void ** data)
/* Events codespace for fd_g_config->cnf_main_ev */
enum {
FDEV_TERMINATE = 1000, /* request to terminate */
FDEV_DUMP_DICT, /* Dump the content of the dictionary */
FDEV_DUMP_EXT, /* Dump state of extensions */
FDEV_DUMP_QUEUES, /* Dump the message queues */
FDEV_DUMP_CONFIG, /* Dump the configuration */
FDEV_DUMP_PEERS /* Dump the list of peers */
FDEV_TERMINATE = 1000 /* request to terminate */
,FDEV_DUMP_DICT /* Dump the content of the dictionary */
,FDEV_DUMP_EXT /* Dump state of extensions */
,FDEV_DUMP_QUEUES /* Dump the message queues */
,FDEV_DUMP_CONFIG /* Dump the configuration */
,FDEV_DUMP_PEERS /* Dump the list of peers */
};
......@@ -160,32 +160,38 @@ enum peer_state {
STATE_REOPEN /* Connection has been re-established, waiting for 3 DWR/DWA exchanges before putting back to service */
};
extern const char *peer_state_str[];
#define STATE_STR(state) \
peer_state_str[ ((unsigned)(state)) <= STATE_REOPEN ? ((unsigned)(state)) : 0 ]
/* Information about a remote peer, used both for query and for creating a new entry */
struct peer_info {
/* This information is always there */
char * pi_diamid; /* UTF-8, \0 terminated. The Diameter Identity of the remote peer */
char * pi_realm; /* idem, its realm. */
/* Flags */
struct {
#define PI_PROT_DEFAULT 0 /* Use the default algorithm configured for the host */
#define PI_PROT_TCP 1
#define PI_PROT_SCTP 2
unsigned proto :2;
#define PI_P3_DEFAULT 0 /* Use the default L3 protocol configured for the host */
#define PI_P3_IP 1 /* Use only IP to connect to this peer */
#define PI_P3_IPv6 2 /* resp, IPv6 */
unsigned pro3 :2;
#define PI_SEC_DEFAULT 0 /* The default behavior configured for the host */
#define PI_P4_DEFAULT 0 /* Use the default L4 proto configured for the host */
#define PI_P4_TCP 1 /* Only use TCP */
#define PI_P4_SCTP 2 /* Only use SCTP */
unsigned pro4 :2;
#define PI_ALGPREF_SCTP 0 /* SCTP is initially attempted */
#define PI_ALGPREF_TCP 1 /* TCP is initially attempted */
unsigned alg :1;
#define PI_SEC_DEFAULT 0 /* New TLS security (dedicated port protecting also CER/CEA) */
#define PI_SEC_NONE 1 /* Transparent security with this peer (IPsec) */
#define PI_SEC_TLS_NEW 2 /* New TLS security (dedicated port protecting also CER/CEA) */
#define PI_SEC_TLS_OLD 3 /* Old TLS security (inband on default port) */
#define PI_SEC_TLS_OLD 2 /* Old TLS security (inband on default port) */
unsigned sec :2;
#define PI_EXP_DEFAULT 0
#define PI_EXP_NONE 1 /* the peer entry does not expire */
#define PI_EXP_INACTIVE 2 /* the peer entry expires after pi_lft seconds without activity */
#define PI_EXP_LIFETIME 3 /* the peer SA information is destroyed after lft seconds (example: DNS timeout) */
unsigned exp :2;
#define PI_EXP_NONE 0 /* the peer entry does not expire */
#define PI_EXP_INACTIVE 1 /* the peer entry expires 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) */
......@@ -231,6 +237,7 @@ extern pthread_rwlock_t fd_g_peers_rw; /* protect the list */
*
* PARAMETERS:
* info : Information to create the peer.
* orig_dbg : A string indicating the origin of the peer information, for debug (ex: conf, redirect, ...)
* cb : optional, a callback to call (once) when the peer connection is established or failed
* cb_data : opaque data to pass to the callback.
*
......@@ -247,7 +254,7 @@ extern pthread_rwlock_t fd_g_peers_rw; /* protect the list */