support for max_connections on listen_endpoint for sslh-ev/sslh-select

This commit is contained in:
yrutschle committed 2025-08-06 09:32:19 +02:00
1 parent 65c9c4ce95
commit 4483e9c7e5
5 files changed
+65 -17

No files matched your search

+1
View File
@@ -109,6 +109,7 @@ struct connection {
struct sslhcfg_protocols_item* proto; /* Where to connect to */
/* SOCK_STREAM */
struct listen_endpoint* endpoint; /* Client-facing listen fd */
enum connection_state state;
time_t probe_timeout;
+22 -13
View File
@@ -22,22 +22,31 @@ connections:
- Use `ulimit` (see bash(3) or your shell's man page) to
limit the number of file descriptors.
- In `sslh-select` and `sslh-ev`, you can set
`max_connections` per protocol, and `sslh` will drop
connections after probing if the count is exceeded.
This should help in keeping SSH connections available even
if an attacker is stuffing other protocols. Currently this
does not work for forking protocols (support is planned)
Then, `sslh` provides several mechanisms to limit the number
of concurrent connections, which in turns limits the number
of file descriptors used.
- `sslh-fork` has an explicit design goal to be as simple as
Essentially there are two ways to do this:
- you can set `max_connections` per protocol, and `sslh`
will drop connections after probing if the count is
exceeded. This should help in keeping SSH connections
available even if an attacker is stuffing other protocols.
Currently this does not work for forking protocols (support
is planned).
- you can set `max_connections` for each `listen` entry. So
the `sslh` process for each port will limit the number of
concurrent connections to that port. This is similar to the
`udp_max_connections` setting, but for TCP.
`sslh-select` and `sslh-ev` support both limit types.
`sslh-fork` has an explicit design goal to be as simple as
possible, which makes it impossible to implement limits per
protocol (because protocol probing is performed after the
process has forked). Instead, you can set `max_connections`
for each `listen` entry. So the `sslh` process for each port
will limit the number of concurrent connections to that
port. Currently this is not supported in `sslh-select` and
`sslh-ev` (support is planned).
process has forked). Limits will only work for `listen`
entries.
As of sslh 2.2.5, this is an experimental feature and not
all use cases have been tested. If 2.2.5 does not exist yet,
+2 -1
View File
@@ -50,6 +50,7 @@ int tidy_connection(struct connection *cnx, struct loop_info* fd_info)
fd_info->num_probing--;
dec_connections(cnx);
dec_listen_connections(cnx);
collection_remove_cnx(fd_info->collection, cnx);
return 0;
@@ -92,7 +93,7 @@ struct connection* cnx_accept_process(struct loop_info* fd_info, struct listen_e
switch (type) {
case SOCK_STREAM:
cnx = accept_new_connection(fd, fd_info);
cnx = accept_new_connection(listen_socket, fd_info);
if (!cnx) return NULL;
break;
+39 -2
View File
@@ -118,12 +118,45 @@ void tcp_read_process(struct loop_info* fd_info,
}
}
/* *cnx must have its endpoint field filled;
* Increment the connection count for the listen endpoint.
* Return 1 if connection count is exceeded, 0 otherwise */
static int inc_listen_connections(struct connection* cnx)
{
cnx->endpoint->num_connections++;
if (cnx->endpoint->endpoint_cfg->max_connections_is_present) {
int num_cnx = cnx->endpoint->num_connections;
int max_cnx = cnx->endpoint->endpoint_cfg->max_connections;
print_message(msg_connections, "Endpoint %d +1: %d/%d cnx\n",
cnx->endpoint->socketfd, num_cnx, max_cnx);
if (num_cnx > max_cnx) {
print_message(msg_connections_error, "Endpoint %d: too many connections, dropping\n", cnx->endpoint->socketfd);
return 1;
}
}
return 0;
}
void dec_listen_connections(struct connection* cnx)
{
cnx->endpoint->num_connections--;
print_message(msg_connections, "Endpoint %d -1: %d/%d cnx\n",
cnx->endpoint->socketfd,
cnx->endpoint->num_connections,
cnx->endpoint->endpoint_cfg->max_connections);
}
/* Accepts a connection from the main socket and assigns it to an empty slot.
* If no slots are available, allocate another few. If that fails, drop the
* connexion */
struct connection* accept_new_connection(int listen_socket, struct loop_info* fd_info)
struct connection* accept_new_connection(struct listen_endpoint* endpoint, struct loop_info* fd_info)
{
int in_socket, res;
int listen_socket = endpoint->socketfd;
print_message(msg_fd, "accepting from %d\n", listen_socket);
@@ -141,12 +174,16 @@ struct connection* accept_new_connection(int listen_socket, struct loop_info* fd
close(in_socket);
return NULL;
}
cnx->endpoint = endpoint;
if (inc_listen_connections(cnx)) {
tidy_connection(cnx, fd_info);
return NULL;
}
add_probing_cnx(fd_info, cnx);
return cnx;
}
/* Connect queue 1 of connection to SSL; returns new file descriptor */
static int connect_queue(struct connection* cnx,
struct loop_info* fd_info)
+1 -1
View File
@@ -6,7 +6,7 @@
#include "tcp-probe.h"
void tcp_read_process(struct loop_info* fd_info, int fd);
struct connection* accept_new_connection(int listen_socket, struct loop_info* fd_info);
struct connection* accept_new_connection(struct listen_endpoint* endpoint, struct loop_info* fd_info);
void probing_read_process(struct connection* cnx, struct loop_info* fd_info);
void cnx_write_process(struct loop_info* fd_info, int fd);