sslh-select: support forking for particular protocols

To keep the code simple, use the same event loop in the child process
as in the parent process but close all irrelevant file descriptors.
This commit is contained in:
Oleg Oshmyan 2017-09-09 00:25:30 +03:00
parent 0929d39a34
commit 2544f20bdf
4 changed files with 35 additions and 12 deletions

20
probe.c
View File

@ -45,16 +45,16 @@ static int is_true(const char *p, int len, struct proto* proto) { return 1; }
/* Table of protocols that have a built-in probe
*/
static struct proto builtins[] = {
/* description service saddr log_level keepalive probe */
{ "ssh", "sshd", NULL, 1, 0, is_ssh_protocol},
{ "openvpn", NULL, NULL, 1, 0, is_openvpn_protocol },
{ "tinc", NULL, NULL, 1, 0, is_tinc_protocol },
{ "xmpp", NULL, NULL, 1, 0, is_xmpp_protocol },
{ "http", NULL, NULL, 1, 0, is_http_protocol },
{ "ssl", NULL, NULL, 1, 0, is_tls_protocol },
{ "tls", NULL, NULL, 1, 0, is_tls_protocol },
{ "adb", NULL, NULL, 1, 0, is_adb_protocol },
{ "anyprot", NULL, NULL, 1, 0, is_true }
/* description service saddr log_level keepalive fork probe */
{ "ssh", "sshd", NULL, 1, 0, 1, is_ssh_protocol},
{ "openvpn", NULL, NULL, 1, 0, 1, is_openvpn_protocol },
{ "tinc", NULL, NULL, 1, 0, 1, is_tinc_protocol },
{ "xmpp", NULL, NULL, 1, 0, 0, is_xmpp_protocol },
{ "http", NULL, NULL, 1, 0, 0, is_http_protocol },
{ "ssl", NULL, NULL, 1, 0, 0, is_tls_protocol },
{ "tls", NULL, NULL, 1, 0, 0, is_tls_protocol },
{ "adb", NULL, NULL, 1, 0, 0, is_adb_protocol },
{ "anyprot", NULL, NULL, 1, 0, 0, is_true }
};
static struct proto *protocols;

View File

@ -24,6 +24,7 @@ struct proto {
* 1: Log incoming connection
*/
int keepalive; /* 0: No keepalive ; 1: Set Keepalive for this connection */
int fork; /* 0: Connection can run within shared process ; 1: Separate process required for this connection */
/* function to probe that protocol; parameters are buffer and length
* containing the data to probe, and a pointer to the protocol structure */

View File

@ -123,14 +123,15 @@ static void printsettings(void)
for (p = get_first_protocol(); p; p = p->next) {
fprintf(stderr,
"%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s]\n",
"%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s] [%s]\n",
p->description,
sprintaddr(buf, sizeof(buf), p->saddr),
p->service,
p->log_level,
p->saddr->ai_family,
p->saddr->ai_addr->sa_family,
p->keepalive ? "keepalive" : "");
p->keepalive ? "keepalive" : "",
p->fork ? "fork" : "");
}
fprintf(stderr, "listening on:\n");
for (a = addr_listen; a; a = a->ai_next) {
@ -307,6 +308,7 @@ static int config_protocols(config_t *config, struct proto **prots)
p->description = name;
config_setting_lookup_string(prot, "service", &(p->service));
config_setting_lookup_bool(prot, "keepalive", &p->keepalive);
config_setting_lookup_bool(prot, "fork", &p->fork);
if (config_setting_lookup_int(prot, "log_level", &p->log_level) == CONFIG_FALSE) {
p->log_level = 1;

View File

@ -27,6 +27,8 @@
const char* server_type = "sslh-select";
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
/* cnx_num_alloc is the number of connection to allocate at once (at start-up,
* and then every time we get too many simultaneous connections: e.g. start
* with 100 slots, then if we get more than 100 connections allocate another
@ -319,6 +321,24 @@ void main_loop(int listen_sockets[], int num_addr_listen)
check_access_rights(in_socket, cnx[i].proto->service)) {
tidy_connection(&cnx[i], &fds_r, &fds_w);
res = -1;
} else if (cnx[i].proto->fork) {
if (!fork()) {
struct connection *cnx_i = &cnx[i];
for (i = 0; i < num_addr_listen; i++) {
FD_CLR(listen_sockets[i], &fds_r);
close(listen_sockets[i]);
}
num_addr_listen = 0;
for (i = 0; i < num_cnx; i++)
if (&cnx[i] != cnx_i)
tidy_connection(&cnx[i], &fds_r, &fds_w);
num_probing = 0;
res = connect_queue(cnx_i, &fds_r, &fds_w);
max_fd = MAX(cnx_i->q[0].fd, cnx_i->q[1].fd) + 1;
} else {
tidy_connection(&cnx[i], &fds_r, &fds_w);
res = -1;
}
} else {
res = connect_queue(&cnx[i], &fds_r, &fds_w);
}