changeset 1396:188c82b6690b

Add ProcessingPeersPattern and ProcessingPeersMinimum parameters. If this is configured, the process will accept all connections from peers matching ProcessingPeersPattern, but will NOT accept connections from other peers until ProcessingPeersMinimum peers of the first type are connected. This allows relays to only go online if there are enough worker peers connected behind them.
author Thomas Klausner <tk@giga.or.at>
date Fri, 15 Nov 2019 11:38:30 +0100
parents 603a72c4bf6c
children 239ba25870d8
files doc/freediameter.conf.sample include/freeDiameter/libfdcore.h libfdcore/config.c libfdcore/fdd.l libfdcore/fdd.y libfdcore/p_ce.c
diffstat 6 files changed, 103 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/doc/freediameter.conf.sample	Fri Nov 15 11:33:48 2019 +0100
+++ b/doc/freediameter.conf.sample	Fri Nov 15 11:38:30 2019 +0100
@@ -88,6 +88,19 @@
 # Default: 5 unidentified clients in paralel.
 #ThreadsPerServer = 5;
 
+# If this host is used as relay or proxy, it can be useful to limit
+# connections from "outside" until enough processing nodes are available.
+# This parameter defines a regex pattern for recognizing such nodes;
+# Default: NO DEFAULT
+#ProcessingPeersPattern = "worker[0-9]*.example.com";
+
+# This next parameter defines how many of these processing peers
+# must be connected before CERs from other hosts are accepted.
+# If this is set, ProcessingPeersPattern must also be defined.
+# If unset or less than 1, ProcessingPeersPattern and this variable do nothing.
+# Default: 0
+#ProcessingPeersMinimum = 0;
+
 ##############################################################
 ##  TLS Configuration
 
--- a/include/freeDiameter/libfdcore.h	Fri Nov 15 11:33:48 2019 +0100
+++ b/include/freeDiameter/libfdcore.h	Fri Nov 15 11:38:30 2019 +0100
@@ -44,6 +44,7 @@
 #include <freeDiameter/libfdproto.h>
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
+#include <regex.h>
 
 /* GNUTLS version */
 #ifndef GNUTLS_VERSION
@@ -132,6 +133,8 @@
 	uint16_t	 cnf_sctp_str;	/* default max number of streams for SCTP associations (def: 30) */
 	struct fd_list	 cnf_endpoints;	/* the local endpoints to bind the server to. list of struct fd_endpoint. default is empty (bind all). After servers are started, this is the actual list of endpoints including port information. */
 	int		 cnf_thr_srv;	/* Number of threads per servers handling the connection state machines */
+	int		 cnf_processing_peers_minimum;	/* Number of processing peers that must be connected before other peers may connect */
+	regex_t		 cnf_processing_peers_pattern_regex;	/* Regex pattern for identifying processing peers */
 	struct fd_list	 cnf_apps;	/* Applications locally supported (except relay, see flags). Use fd_disp_app_support to add one. list of struct fd_app. */
 	uint16_t	 cnf_dispthr;	/* Number of dispatch threads to create */
 	uint16_t	 cnf_rr_in_answers;	/* include Route-Record AVP in answers */
--- a/libfdcore/config.c	Fri Nov 15 11:33:48 2019 +0100
+++ b/libfdcore/config.c	Fri Nov 15 11:38:30 2019 +0100
@@ -59,6 +59,7 @@
 	fd_g_config->cnf_port_tls = DIAMETER_SECURE_PORT;
 	fd_g_config->cnf_sctp_str = 30;
 	fd_g_config->cnf_thr_srv  = 5;
+	fd_g_config->cnf_processing_peers_minimum = 0;
 	fd_g_config->cnf_dispthr  = 4;
 	fd_list_init(&fd_g_config->cnf_endpoints, NULL);
 	fd_list_init(&fd_g_config->cnf_apps, NULL);
@@ -101,6 +102,7 @@
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of SCTP streams . : %hu\n", fd_g_config->cnf_sctp_str), return NULL);
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of clients thr .. : %d\n", fd_g_config->cnf_thr_srv), return NULL);
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of app threads .. : %hu\n", fd_g_config->cnf_dispthr), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Minimal processing peers : %hu\n", fd_g_config->cnf_processing_peers_minimum), return NULL);
 	if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local endpoints ........ : Default (use all available)\n"), return NULL);
 	} else {
--- a/libfdcore/fdd.l	Fri Nov 15 11:33:48 2019 +0100
+++ b/libfdcore/fdd.l	Fri Nov 15 11:38:30 2019 +0100
@@ -256,6 +256,8 @@
 (?i:"AppServThreads")	{ return APPSERVTHREADS; }
 (?i:"ListenOn")		{ return LISTENON; }
 (?i:"ThreadsPerServer")	{ return THRPERSRV; }
+(?i:"ProcessingPeersPattern")	{ return PROCESSINGPEERSPATTERN; }
+(?i:"ProcessingPeersMinimum")	{ return PROCESSINGPEERSMINIMUM; }
 (?i:"TcTimer")		{ return TCTIMER; }
 (?i:"TwTimer")		{ return TWTIMER; }
 (?i:"NoRelay")		{ return NORELAY; }
--- a/libfdcore/fdd.y	Fri Nov 15 11:33:48 2019 +0100
+++ b/libfdcore/fdd.y	Fri Nov 15 11:38:30 2019 +0100
@@ -109,6 +109,8 @@
 %token		APPSERVTHREADS
 %token		LISTENON
 %token		THRPERSRV
+%token		PROCESSINGPEERSPATTERN
+%token		PROCESSINGPEERSMINIMUM
 %token		TCTIMER
 %token		TWTIMER
 %token		NORELAY
@@ -141,6 +143,8 @@
 			| conffile sctpstreams
 			| conffile listenon
 			| conffile thrpersrv
+			| conffile processingpeerspattern
+			| conffile processingpeersminimum
 			| conffile norelay
 			| conffile appservthreads
 			| conffile noip
@@ -252,6 +256,45 @@
 			}
 			;
 
+processingpeerspattern:		PROCESSINGPEERSPATTERN '=' QSTRING ';'
+			{
+				char *pattern = $3;
+				int err;
+				CHECK_FCT_DO( err=regcomp(&conf->cnf_processing_peers_pattern_regex, pattern, REG_EXTENDED | REG_NOSUB),
+					{
+						char * buf;
+						size_t bl;
+
+						/* Error while compiling the regex */
+						TRACE_DEBUG(INFO, "error while compiling the regular expression '%s':", pattern);
+
+						/* Get the error message size */
+						bl = regerror(err, &conf->cnf_processing_peers_pattern_regex, NULL, 0);
+
+						/* Alloc the buffer for error message */
+						CHECK_MALLOC( buf = malloc(bl) );
+
+						/* Get the error message content */
+						regerror(err, &conf->cnf_processing_peers_pattern_regex, buf, bl);
+						TRACE_DEBUG(INFO, "\t%s", buf);
+
+						/* Free the buffer, return the error */
+						free(buf);
+
+						yyerror (&yylloc, conf, "Invalid regular expression in ProcessingPeersPattern");
+						YYERROR;
+					} );
+			}
+			;
+
+processingpeersminimum:		PROCESSINGPEERSMINIMUM '=' INTEGER ';'
+			{
+				CHECK_PARAMS_DO( ($3 >= 0),
+					{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
+				conf->cnf_processing_peers_minimum = $3;
+			}
+			;
+
 norelay:		NORELAY ';'
 			{
 				conf->cnf_flags.no_fwd = 1;
--- a/libfdcore/p_ce.c	Fri Nov 15 11:33:48 2019 +0100
+++ b/libfdcore/p_ce.c	Fri Nov 15 11:38:30 2019 +0100
@@ -833,6 +833,26 @@
 	return 0;
 }
 
+/* Check if enough processing peers are connected to allow connections by other peers */
+static int sufficient_processing_peers(void) {
+	int processing_peers_count = 0;
+	struct fd_list * li;
+
+	CHECK_FCT( pthread_rwlock_rdlock(&fd_g_activ_peers_rw) );
+	for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) {
+		struct fd_peer * p = (struct fd_peer *)li->o;
+
+		TRACE_DEBUG(FULL, "comparing '%s' against processing peers pattern", p->p_hdr.info.pi_diamid);
+		if (regexec(&fd_g_config->cnf_processing_peers_pattern_regex, p->p_hdr.info.pi_diamid, 0, NULL, 0) == 0) {
+			processing_peers_count++;
+		}
+	}
+	CHECK_FCT( pthread_rwlock_unlock(&fd_g_activ_peers_rw) );
+
+	TRACE_DEBUG(FULL, "%d processing peers found", processing_peers_count);
+	return (processing_peers_count >= fd_g_config->cnf_processing_peers_minimum);
+}
+
 /* Handle the receiver side to go to OPEN or OPEN_NEW state (any election is resolved) */
 int fd_p_ce_process_receiver(struct fd_peer * peer)
 {
@@ -883,6 +903,26 @@
 		CHECK_FCT( res );
 	}
 	
+	/* Check peer type and if enough processing peers are already connected */
+	if (fd_g_config->cnf_processing_peers_minimum > 0) {
+		if (regexec(&fd_g_config->cnf_processing_peers_pattern_regex, peer->p_hdr.info.pi_diamid, 0, NULL, 0) != 0) {
+			/* peer is not a processing peer */
+			if (!sufficient_processing_peers()) {
+				pei.pei_errcode = "DIAMETER_TOO_BUSY";
+				goto error_abort;
+			}
+		}
+	}
+
+	if (peer->p_flags.pf_responder) {
+		int res = fd_peer_validate( peer );
+		if (res < 0) {
+			TRACE_DEBUG(INFO, "Rejected CER from peer '%s', validation failed (returning DIAMETER_UNKNOWN_PEER).", peer->p_hdr.info.pi_diamid);
+			pei.pei_errcode = "DIAMETER_UNKNOWN_PEER";
+			goto error_abort;
+		}
+		CHECK_FCT( res );
+	}
 	/* Check if we have common applications */
 	if ( fd_g_config->cnf_flags.no_fwd && (! peer->p_hdr.info.runtime.pir_relay) ) {
 		int got_common;
"Welcome to our mercurial repository"