Просмотр исходного кода

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 13 лет назад
Родитель
Сommit
61f8b97041
9 измененных файлов с 92 добавлено и 8 удалено
  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_CON_LIFETIME	"tcp_connection_lifetime"
 TCP_POLL_METHOD		"tcp_poll_method"
 TCP_POLL_METHOD		"tcp_poll_method"
 TCP_MAX_CONNECTIONS	"tcp_max_connections"
 TCP_MAX_CONNECTIONS	"tcp_max_connections"
+TLS_MAX_CONNECTIONS	"tls_max_connections"
 TCP_NO_CONNECT		"tcp_no_connect"
 TCP_NO_CONNECT		"tcp_no_connect"
 TCP_SOURCE_IPV4		"tcp_source_ipv4"
 TCP_SOURCE_IPV4		"tcp_source_ipv4"
 TCP_SOURCE_IPV6		"tcp_source_ipv6"
 TCP_SOURCE_IPV6		"tcp_source_ipv6"
@@ -805,6 +806,8 @@ IMPORTFILE      "import_file"
 									return TCP_POLL_METHOD; }
 									return TCP_POLL_METHOD; }
 <INITIAL>{TCP_MAX_CONNECTIONS}	{ count(); yylval.strval=yytext;
 <INITIAL>{TCP_MAX_CONNECTIONS}	{ count(); yylval.strval=yytext;
 									return TCP_MAX_CONNECTIONS; }
 									return TCP_MAX_CONNECTIONS; }
+<INITIAL>{TLS_MAX_CONNECTIONS}	{ count(); yylval.strval=yytext;
+									return TLS_MAX_CONNECTIONS; }
 <INITIAL>{TCP_NO_CONNECT}		{ count(); yylval.strval=yytext;
 <INITIAL>{TCP_NO_CONNECT}		{ count(); yylval.strval=yytext;
 									return TCP_NO_CONNECT; }
 									return TCP_NO_CONNECT; }
 <INITIAL>{TCP_SOURCE_IPV4}		{ count(); yylval.strval=yytext;
 <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_CON_LIFETIME
 %token TCP_POLL_METHOD
 %token TCP_POLL_METHOD
 %token TCP_MAX_CONNECTIONS
 %token TCP_MAX_CONNECTIONS
+%token TLS_MAX_CONNECTIONS
 %token TCP_NO_CONNECT
 %token TCP_NO_CONNECT
 %token TCP_SOURCE_IPV4
 %token TCP_SOURCE_IPV4
 %token TCP_SOURCE_IPV6
 %token TCP_SOURCE_IPV6
@@ -1063,6 +1064,14 @@ assign_stm:
 		#endif
 		#endif
 	}
 	}
 	| TCP_MAX_CONNECTIONS EQUAL error { yyerror("number expected"); }
 	| 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 {
 	| TCP_NO_CONNECT EQUAL NUMBER {
 		#ifdef USE_TCP
 		#ifdef USE_TCP
 			tcp_default_cfg.no_connect=$3;
 			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){
 	if (!tcp_disable){
 		tcp_get_info(&ti);
 		tcp_get_info(&ti);
 		rpc->add(c, "{", &handle);
 		rpc->add(c, "{", &handle);
-		rpc->struct_add(handle, "dddd",
+		rpc->struct_add(handle, "dddddd",
 			"readers", ti.tcp_readers,
 			"readers", ti.tcp_readers,
 			"max_connections", ti.tcp_max_connections,
 			"max_connections", ti.tcp_max_connections,
+			"max_tls_connections", ti.tls_max_connections,
 			"opened_connections", ti.tcp_connections_no,
 			"opened_connections", ti.tcp_connections_no,
+			"opened_tls_connections", ti.tls_connections_no,
 			"write_queued_bytes", ti.tcp_write_queued
 			"write_queued_bytes", ti.tcp_write_queued
 		);
 		);
 	}else{
 	}else{
@@ -707,11 +709,12 @@ static void core_tcp_options(rpc_t* rpc, void* c)
 	if (!tcp_disable){
 	if (!tcp_disable){
 		tcp_options_get(&t);
 		tcp_options_get(&t);
 		rpc->add(c, "{", &handle);
 		rpc->add(c, "{", &handle);
-		rpc->struct_add(handle, "dddddddddddddddddddddd",
+		rpc->struct_add(handle, "ddddddddddddddddddddddd",
 			"connect_timeout", t.connect_timeout_s,
 			"connect_timeout", t.connect_timeout_s,
 			"send_timeout",  TICKS_TO_S(t.send_timeout),
 			"send_timeout",  TICKS_TO_S(t.send_timeout),
 			"connection_lifetime",  TICKS_TO_S(t.con_lifetime),
 			"connection_lifetime",  TICKS_TO_S(t.con_lifetime),
 			"max_connections(soft)", t.max_connections,
 			"max_connections(soft)", t.max_connections,
+			"max_tls_connections(soft)", t.max_tls_connections,
 			"no_connect",	t.no_connect,
 			"no_connect",	t.no_connect,
 			"fd_cache",		t.fd_cache,
 			"fd_cache",		t.fd_cache,
 			"async",		t.async,
 			"async",		t.async,

+ 2 - 1
globals.h

@@ -93,7 +93,8 @@ extern int tcp_main_pid;
 extern int tcp_children_no;
 extern int tcp_children_no;
 extern int tcp_disable;
 extern int tcp_disable;
 extern enum poll_types tcp_poll_method;
 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
 #endif
 #ifdef USE_TLS
 #ifdef USE_TLS
 extern int tls_disable;
 extern int tls_disable;

+ 3 - 1
tcp_info.h

@@ -34,7 +34,9 @@
 struct tcp_gen_info{
 struct tcp_gen_info{
 	int tcp_readers;
 	int tcp_readers;
 	int tcp_max_connections; /* startup connection limit, cannot be exceeded*/
 	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
 	int tcp_write_queued; /* total bytes queued for write, 0 if no
 							 write queued support is enabled */
 							 write queued support is enabled */
 };
 };

+ 3 - 1
tcp_init.h

@@ -37,7 +37,9 @@
 									   timeout */
 									   timeout */
 #define DEFAULT_TCP_CONNECT_TIMEOUT 10 /* if a connect doesn't complete in this
 #define DEFAULT_TCP_CONNECT_TIMEOUT 10 /* if a connect doesn't complete in this
 										  time, timeout */
 										  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 */
 #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 */
 enum poll_types tcp_poll_method=0; /* by default choose the best method */
 int tcp_main_max_fd_no=0;
 int tcp_main_max_fd_no=0;
 int tcp_max_connections=DEFAULT_TCP_MAX_CONNECTIONS;
 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_addr; /* saved bind/srv v4 addr. */
 static union sockaddr_union* tcp_source_ipv4=0;
 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;
 static union sockaddr_union* tcp_source_ipv6=0;
 #endif
 #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 */
 /* connection hash table (after ip&port) , includes also aliases */
 struct tcp_conn_alias** tcpconn_aliases_hash=0;
 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));
 					cfg_get(tcp, tcp_cfg, max_connections));
 		goto error;
 		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);
 	s=tcp_do_connect(server, from, type,  send_flags, &my_name, &si, &state);
 	if (s==-1){
 	if (s==-1){
 		LOG(L_ERR, "ERROR: tcp_do_connect %s: failed (%d) %s\n",
 		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));
 							cfg_get(tcp, tcp_cfg, max_connections));
 				return -1;
 				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,
 			c=tcpconn_new(-1, &dst->to, from, 0, dst->proto,
 							S_CONN_CONNECT);
 							S_CONN_CONNECT);
 			if (unlikely(c==0)){
 			if (unlikely(c==0)){
@@ -2992,6 +3015,8 @@ inline static void tcpconn_destroy(struct tcp_connection* tcpconn)
 			tcpconn_close_main_fd(tcpconn);
 			tcpconn_close_main_fd(tcpconn);
 			tcpconn->flags|=F_CONN_FD_CLOSED;
 			tcpconn->flags|=F_CONN_FD_CLOSED;
 			(*tcp_connections_no)--;
 			(*tcp_connections_no)--;
+			if (unlikely(tcpconn->type==PROTO_TLS))
+				(*tls_connections_no)--;
 		}
 		}
 		_tcpconn_free(tcpconn); /* destroys also the wbuf_q if still present*/
 		_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_close_main_fd(tcpconn);
 		tcpconn->flags|=F_CONN_FD_CLOSED;
 		tcpconn->flags|=F_CONN_FD_CLOSED;
 		(*tcp_connections_no)--;
 		(*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
 	/* 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
 	 * 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;
 				break;
 			}
 			}
 			(*tcp_connections_no)++;
 			(*tcp_connections_no)++;
+			if (unlikely(tcpconn->type==PROTO_TLS))
+				(*tls_connections_no)++;
 			tcpconn->s=fd;
 			tcpconn->s=fd;
 			/* add tcpconn to the list*/
 			/* add tcpconn to the list*/
 			tcpconn_add(tcpconn);
 			tcpconn_add(tcpconn);
@@ -3787,6 +3816,8 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
 				break;
 				break;
 			}
 			}
 			(*tcp_connections_no)++;
 			(*tcp_connections_no)++;
+			if (unlikely(tcpconn->type==PROTO_TLS))
+				(*tls_connections_no)++;
 			tcpconn->s=fd;
 			tcpconn->s=fd;
 			/* update the timeout*/
 			/* update the timeout*/
 			t=get_ticks_raw();
 			t=get_ticks_raw();
@@ -3974,12 +4005,24 @@ static inline int handle_new_connect(struct socket_info* si)
 		TCP_STATS_LOCAL_REJECT();
 		TCP_STATS_LOCAL_REJECT();
 		return 1; /* success, because the accept was succesfull */
 		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)){
 	if (unlikely(init_sock_opt_accept(new_sock)<0)){
 		LOG(L_ERR, "ERROR: handle_new_connect: init_sock_opt failed\n");
 		LOG(L_ERR, "ERROR: handle_new_connect: init_sock_opt failed\n");
 		tcp_safe_close(new_sock);
 		tcp_safe_close(new_sock);
 		return 1; /* success, because the accept was succesfull */
 		return 1; /* success, because the accept was succesfull */
 	}
 	}
 	(*tcp_connections_no)++;
 	(*tcp_connections_no)++;
+	if (unlikely(si->proto==PROTO_TLS))
+		(*tls_connections_no)++;
 	/* stats for established connections are incremented after
 	/* stats for established connections are incremented after
 	   the first received or sent packet.
 	   the first received or sent packet.
 	   Alternatively they could be incremented here for accepted
 	   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");
 				"closing socket\n");
 		tcp_safe_close(new_sock);
 		tcp_safe_close(new_sock);
 		(*tcp_connections_no)--;
 		(*tcp_connections_no)--;
+		if (unlikely(si->proto==PROTO_TLS))
+			(*tls_connections_no)--;
 	}
 	}
 	return 1; /* accept() was succesfull */
 	return 1; /* accept() was succesfull */
 }
 }
@@ -4428,6 +4473,8 @@ static inline void tcpconn_destroy_all()
 					tcp_safe_close(fd);
 					tcp_safe_close(fd);
 				}
 				}
 				(*tcp_connections_no)--;
 				(*tcp_connections_no)--;
+				if (unlikely(c->type==PROTO_TLS))
+					(*tls_connections_no)--;
 			c=next;
 			c=next;
 		}
 		}
 	}
 	}
@@ -4621,6 +4668,10 @@ void destroy_tcp()
 			shm_free(tcp_connections_no);
 			shm_free(tcp_connections_no);
 			tcp_connections_no=0;
 			tcp_connections_no=0;
 		}
 		}
+		if (tls_connections_no){
+			shm_free(tls_connections_no);
+			tls_connections_no=0;
+		}
 #ifdef TCP_ASYNC
 #ifdef TCP_ASYNC
 		if (tcp_total_wq){
 		if (tcp_total_wq){
 			shm_free(tcp_total_wq);
 			shm_free(tcp_total_wq);
@@ -4677,6 +4728,12 @@ int init_tcp()
 		goto error;
 		goto error;
 	}
 	}
 	*tcp_connections_no=0;
 	*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;
 	if (INIT_TCP_STATS()!=0) goto error;
 	connection_id=shm_malloc(sizeof(int));
 	connection_id=shm_malloc(sizeof(int));
 	if (connection_id==0){
 	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_readers=tcp_children_no;
 	ti->tcp_max_connections=tcp_max_connections;
 	ti->tcp_max_connections=tcp_max_connections;
+	ti->tls_max_connections=tls_max_connections;
 	ti->tcp_connections_no=*tcp_connections_no;
 	ti->tcp_connections_no=*tcp_connections_no;
+	ti->tls_connections_no=*tls_connections_no;
 #ifdef TCP_ASYNC
 #ifdef TCP_ASYNC
 	ti->tcp_write_queued=*tcp_total_wq;
 	ti->tcp_write_queued=*tcp_total_wq;
 #else
 #else

+ 5 - 1
tcp_options.c

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

+ 2 - 1
tcp_options.h

@@ -114,7 +114,8 @@ struct cfg_group_tcp{
 	int connect_timeout_s; /* in s */
 	int connect_timeout_s; /* in s */
 	int send_timeout; /* in ticks (s fixed to ticks) */
 	int send_timeout; /* in ticks (s fixed to ticks) */
 	int con_lifetime; /* 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 no_connect; /* do not open any new tcp connection (but accept them) */
 	int fd_cache; /* on /off */
 	int fd_cache; /* on /off */
 	/* tcp async options */
 	/* tcp async options */