Parcourir la source

core/tcp/tls: added tls_max_connections global parameter

- set a limit to active tls connections
- its management is done in tcp code, as tls is encryption layer over
  tcp
- tls connections are still counted as tcp connections, thus this limit
  cannot exceed tcp_max_connections
- default value 2048
- core.tcp_options lists also the tls connections number
Daniel-Constantin Mierla il y a 13 ans
Parent
commit
61f8b97041
9 fichiers modifiés avec 92 ajouts et 8 suppressions
  1. 3 0
      cfg.lex
  2. 9 0
      cfg.y
  3. 5 2
      core_cmd.c
  4. 2 1
      globals.h
  5. 3 1
      tcp_info.h
  6. 3 1
      tcp_init.h
  7. 60 1
      tcp_main.c
  8. 5 1
      tcp_options.c
  9. 2 1
      tcp_options.h

+ 3 - 0
cfg.lex

@@ -414,6 +414,7 @@ TCP_CONNECT_TIMEOUT	"tcp_connect_timeout"
 TCP_CON_LIFETIME	"tcp_connection_lifetime"
 TCP_POLL_METHOD		"tcp_poll_method"
 TCP_MAX_CONNECTIONS	"tcp_max_connections"
+TLS_MAX_CONNECTIONS	"tls_max_connections"
 TCP_NO_CONNECT		"tcp_no_connect"
 TCP_SOURCE_IPV4		"tcp_source_ipv4"
 TCP_SOURCE_IPV6		"tcp_source_ipv6"
@@ -805,6 +806,8 @@ IMPORTFILE      "import_file"
 									return TCP_POLL_METHOD; }
 <INITIAL>{TCP_MAX_CONNECTIONS}	{ count(); yylval.strval=yytext;
 									return TCP_MAX_CONNECTIONS; }
+<INITIAL>{TLS_MAX_CONNECTIONS}	{ count(); yylval.strval=yytext;
+									return TLS_MAX_CONNECTIONS; }
 <INITIAL>{TCP_NO_CONNECT}		{ count(); yylval.strval=yytext;
 									return TCP_NO_CONNECT; }
 <INITIAL>{TCP_SOURCE_IPV4}		{ count(); yylval.strval=yytext;

+ 9 - 0
cfg.y

@@ -472,6 +472,7 @@ extern char *finame;
 %token TCP_CON_LIFETIME
 %token TCP_POLL_METHOD
 %token TCP_MAX_CONNECTIONS
+%token TLS_MAX_CONNECTIONS
 %token TCP_NO_CONNECT
 %token TCP_SOURCE_IPV4
 %token TCP_SOURCE_IPV6
@@ -1063,6 +1064,14 @@ assign_stm:
 		#endif
 	}
 	| TCP_MAX_CONNECTIONS EQUAL error { yyerror("number expected"); }
+	| TLS_MAX_CONNECTIONS EQUAL NUMBER {
+		#ifdef USE_TLS
+			tls_max_connections=$3;
+		#else
+			warn("tls support not compiled in");
+		#endif
+	}
+	| TLS_MAX_CONNECTIONS EQUAL error { yyerror("number expected"); }
 	| TCP_NO_CONNECT EQUAL NUMBER {
 		#ifdef USE_TCP
 			tcp_default_cfg.no_connect=$3;

+ 5 - 2
core_cmd.c

@@ -677,10 +677,12 @@ static void core_tcpinfo(rpc_t* rpc, void* c)
 	if (!tcp_disable){
 		tcp_get_info(&ti);
 		rpc->add(c, "{", &handle);
-		rpc->struct_add(handle, "dddd",
+		rpc->struct_add(handle, "dddddd",
 			"readers", ti.tcp_readers,
 			"max_connections", ti.tcp_max_connections,
+			"max_tls_connections", ti.tls_max_connections,
 			"opened_connections", ti.tcp_connections_no,
+			"opened_tls_connections", ti.tls_connections_no,
 			"write_queued_bytes", ti.tcp_write_queued
 		);
 	}else{
@@ -707,11 +709,12 @@ static void core_tcp_options(rpc_t* rpc, void* c)
 	if (!tcp_disable){
 		tcp_options_get(&t);
 		rpc->add(c, "{", &handle);
-		rpc->struct_add(handle, "dddddddddddddddddddddd",
+		rpc->struct_add(handle, "ddddddddddddddddddddddd",
 			"connect_timeout", t.connect_timeout_s,
 			"send_timeout",  TICKS_TO_S(t.send_timeout),
 			"connection_lifetime",  TICKS_TO_S(t.con_lifetime),
 			"max_connections(soft)", t.max_connections,
+			"max_tls_connections(soft)", t.max_tls_connections,
 			"no_connect",	t.no_connect,
 			"fd_cache",		t.fd_cache,
 			"async",		t.async,

+ 2 - 1
globals.h

@@ -93,7 +93,8 @@ extern int tcp_main_pid;
 extern int tcp_children_no;
 extern int tcp_disable;
 extern enum poll_types tcp_poll_method;
-extern int tcp_max_connections; /* maximum connections, hard limit */
+extern int tcp_max_connections; /* maximum tcp connections, hard limit */
+extern int tls_max_connections; /* maximum tls connections, hard limit */
 #endif
 #ifdef USE_TLS
 extern int tls_disable;

+ 3 - 1
tcp_info.h

@@ -34,7 +34,9 @@
 struct tcp_gen_info{
 	int tcp_readers;
 	int tcp_max_connections; /* startup connection limit, cannot be exceeded*/
-	int tcp_connections_no; /* crt. number */
+	int tls_max_connections; /* startup tls limit, cannot exceed tcp limit*/
+	int tcp_connections_no; /* crt. connections number */
+	int tls_connections_no; /* crt. tls connections number */
 	int tcp_write_queued; /* total bytes queued for write, 0 if no
 							 write queued support is enabled */
 };

+ 3 - 1
tcp_init.h

@@ -37,7 +37,9 @@
 									   timeout */
 #define DEFAULT_TCP_CONNECT_TIMEOUT 10 /* if a connect doesn't complete in this
 										  time, timeout */
-#define DEFAULT_TCP_MAX_CONNECTIONS 2048 /* maximum connections */
+#define DEFAULT_TCP_MAX_CONNECTIONS 2048 /* maximum tcp connections */
+
+#define DEFAULT_TLS_MAX_CONNECTIONS 2048 /* maximum tls connections */
 
 #define DEFAULT_TCP_BUF_SIZE	4096  /* buffer size used for reads */
 

+ 60 - 1
tcp_main.c

@@ -250,6 +250,7 @@ static int is_tcp_main=0;
 enum poll_types tcp_poll_method=0; /* by default choose the best method */
 int tcp_main_max_fd_no=0;
 int tcp_max_connections=DEFAULT_TCP_MAX_CONNECTIONS;
+int tls_max_connections=DEFAULT_TLS_MAX_CONNECTIONS;
 
 static union sockaddr_union tcp_source_ipv4_addr; /* saved bind/srv v4 addr. */
 static union sockaddr_union* tcp_source_ipv4=0;
@@ -258,7 +259,8 @@ static union sockaddr_union tcp_source_ipv6_addr; /* saved bind/src v6 addr. */
 static union sockaddr_union* tcp_source_ipv6=0;
 #endif
 
-static int* tcp_connections_no=0; /* current open connections */
+static int* tcp_connections_no=0; /* current tcp (+tls) open connections */
+static int* tls_connections_no=0; /* current tls open connections */
 
 /* connection hash table (after ip&port) , includes also aliases */
 struct tcp_conn_alias** tcpconn_aliases_hash=0;
@@ -1261,6 +1263,16 @@ struct tcp_connection* tcpconn_connect( union sockaddr_union* server,
 					cfg_get(tcp, tcp_cfg, max_connections));
 		goto error;
 	}
+	if (unlikely(type==PROTO_TLS)) {
+		if (*tls_connections_no >= cfg_get(tcp, tcp_cfg, max_tls_connections)){
+			LM_ERR("ERROR: maximum number of tls connections"
+						" exceeded (%d/%d)\n",
+						*tls_connections_no,
+						cfg_get(tcp, tcp_cfg, max_tls_connections));
+			goto error;
+		}
+	}
+
 	s=tcp_do_connect(server, from, type,  send_flags, &my_name, &si, &state);
 	if (s==-1){
 		LOG(L_ERR, "ERROR: tcp_do_connect %s: failed (%d) %s\n",
@@ -1849,6 +1861,17 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
 							cfg_get(tcp, tcp_cfg, max_connections));
 				return -1;
 			}
+			if (unlikely(dst->proto==PROTO_TLS)) {
+				if (unlikely(*tls_connections_no >=
+							cfg_get(tcp, tcp_cfg, max_tls_connections))){
+					LM_ERR("tcp_send %s: maximum number of"
+							" tls connections exceeded (%d/%d)\n",
+							su2a(&dst->to, sizeof(dst->to)),
+							*tls_connections_no,
+							cfg_get(tcp, tcp_cfg, max_tls_connections));
+					return -1;
+				}
+			}
 			c=tcpconn_new(-1, &dst->to, from, 0, dst->proto,
 							S_CONN_CONNECT);
 			if (unlikely(c==0)){
@@ -2992,6 +3015,8 @@ inline static void tcpconn_destroy(struct tcp_connection* tcpconn)
 			tcpconn_close_main_fd(tcpconn);
 			tcpconn->flags|=F_CONN_FD_CLOSED;
 			(*tcp_connections_no)--;
+			if (unlikely(tcpconn->type==PROTO_TLS))
+				(*tls_connections_no)--;
 		}
 		_tcpconn_free(tcpconn); /* destroys also the wbuf_q if still present*/
 }
@@ -3038,6 +3063,8 @@ inline static int tcpconn_put_destroy(struct tcp_connection* tcpconn)
 		tcpconn_close_main_fd(tcpconn);
 		tcpconn->flags|=F_CONN_FD_CLOSED;
 		(*tcp_connections_no)--;
+		if (unlikely(tcpconn->type==PROTO_TLS))
+				(*tls_connections_no)--;
 	}
 	/* all the flags / ops on the tcpconn must be done prior to decrementing
 	 * the refcnt. and at least a membar_write_atomic_op() mem. barrier or
@@ -3656,6 +3683,8 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
 				break;
 			}
 			(*tcp_connections_no)++;
+			if (unlikely(tcpconn->type==PROTO_TLS))
+				(*tls_connections_no)++;
 			tcpconn->s=fd;
 			/* add tcpconn to the list*/
 			tcpconn_add(tcpconn);
@@ -3787,6 +3816,8 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
 				break;
 			}
 			(*tcp_connections_no)++;
+			if (unlikely(tcpconn->type==PROTO_TLS))
+				(*tls_connections_no)++;
 			tcpconn->s=fd;
 			/* update the timeout*/
 			t=get_ticks_raw();
@@ -3974,12 +4005,24 @@ static inline int handle_new_connect(struct socket_info* si)
 		TCP_STATS_LOCAL_REJECT();
 		return 1; /* success, because the accept was succesfull */
 	}
+	if (unlikely(si->proto==PROTO_TLS)) {
+		if (unlikely(*tls_connections_no>=cfg_get(tcp, tcp_cfg, max_tls_connections))){
+			LM_ERR("maximum number of tls connections exceeded: %d/%d\n",
+					*tls_connections_no,
+					cfg_get(tcp, tcp_cfg, max_tls_connections));
+			tcp_safe_close(new_sock);
+			TCP_STATS_LOCAL_REJECT();
+			return 1; /* success, because the accept was succesfull */
+		}
+	}
 	if (unlikely(init_sock_opt_accept(new_sock)<0)){
 		LOG(L_ERR, "ERROR: handle_new_connect: init_sock_opt failed\n");
 		tcp_safe_close(new_sock);
 		return 1; /* success, because the accept was succesfull */
 	}
 	(*tcp_connections_no)++;
+	if (unlikely(si->proto==PROTO_TLS))
+		(*tls_connections_no)++;
 	/* stats for established connections are incremented after
 	   the first received or sent packet.
 	   Alternatively they could be incremented here for accepted
@@ -4044,6 +4087,8 @@ static inline int handle_new_connect(struct socket_info* si)
 				"closing socket\n");
 		tcp_safe_close(new_sock);
 		(*tcp_connections_no)--;
+		if (unlikely(si->proto==PROTO_TLS))
+			(*tls_connections_no)--;
 	}
 	return 1; /* accept() was succesfull */
 }
@@ -4428,6 +4473,8 @@ static inline void tcpconn_destroy_all()
 					tcp_safe_close(fd);
 				}
 				(*tcp_connections_no)--;
+				if (unlikely(c->type==PROTO_TLS))
+					(*tls_connections_no)--;
 			c=next;
 		}
 	}
@@ -4621,6 +4668,10 @@ void destroy_tcp()
 			shm_free(tcp_connections_no);
 			tcp_connections_no=0;
 		}
+		if (tls_connections_no){
+			shm_free(tls_connections_no);
+			tls_connections_no=0;
+		}
 #ifdef TCP_ASYNC
 		if (tcp_total_wq){
 			shm_free(tcp_total_wq);
@@ -4677,6 +4728,12 @@ int init_tcp()
 		goto error;
 	}
 	*tcp_connections_no=0;
+	tls_connections_no=shm_malloc(sizeof(int));
+	if (tls_connections_no==0){
+		LOG(L_CRIT, "ERROR: init_tcp: could not alloc globals\n");
+		goto error;
+	}
+	*tls_connections_no=0;
 	if (INIT_TCP_STATS()!=0) goto error;
 	connection_id=shm_malloc(sizeof(int));
 	if (connection_id==0){
@@ -4838,7 +4895,9 @@ void tcp_get_info(struct tcp_gen_info *ti)
 {
 	ti->tcp_readers=tcp_children_no;
 	ti->tcp_max_connections=tcp_max_connections;
+	ti->tls_max_connections=tls_max_connections;
 	ti->tcp_connections_no=*tcp_connections_no;
+	ti->tls_connections_no=*tls_connections_no;
 #ifdef TCP_ASYNC
 	ti->tcp_write_queued=*tcp_total_wq;
 #else

+ 5 - 1
tcp_options.c

@@ -69,7 +69,10 @@ static cfg_def_t tcp_cfg_def[] = {
 		"connection lifetime (in seconds)"},
 	{ "max_connections", CFG_VAR_INT | CFG_ATOMIC, 0, (1U<<31)-1,
 													       fix_max_conns,    0,
-		"maximum connection number, soft limit"},
+		"maximum tcp connections number, soft limit"},
+	{ "max_tls_connections", CFG_VAR_INT | CFG_ATOMIC, 0, (1U<<31)-1,
+													       fix_max_conns,    0,
+		"maximum tls connections number, soft limit"},
 	{ "no_connect",   CFG_VAR_INT | CFG_ATOMIC,      0,   1,      0,         0,
 		"if set only accept new connections, never actively open new ones"},
 	{ "fd_cache",     CFG_VAR_INT | CFG_READONLY,    0,   1,      0,         0,
@@ -132,6 +135,7 @@ void init_tcp_options()
 	tcp_default_cfg.con_lifetime=S_TO_TICKS(DEFAULT_TCP_CONNECTION_LIFETIME_S);
 #ifdef USE_TCP
 	tcp_default_cfg.max_connections=tcp_max_connections;
+	tcp_default_cfg.max_tls_connections=tls_max_connections;
 #else /*USE_TCP*/
 	tcp_default_cfg.max_connections=0;
 #endif /*USE_TCP*/

+ 2 - 1
tcp_options.h

@@ -114,7 +114,8 @@ struct cfg_group_tcp{
 	int connect_timeout_s; /* in s */
 	int send_timeout; /* in ticks (s fixed to ticks) */
 	int con_lifetime; /* in ticks (s fixed to ticks) */
-	int max_connections;
+	int max_connections; /* max tcp connections (includes tls connections) */
+	int max_tls_connections; /* max tls connections */
 	int no_connect; /* do not open any new tcp connection (but accept them) */
 	int fd_cache; /* on /off */
 	/* tcp async options */